diff --git a/CHANGELOG.md b/CHANGELOG.md index 714e44aa..a63fd603 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,28 @@ ### Added +- Executable-operation packages can now bind an exact compiler-owned + `edict.result-projection.artifact/v1`. Projected invocations retain the exact + canonical application input, scheduler-owned private evaluation emits the + compiler-declared output type and canonical result bytes, and a + domain-separated identity binds that evidence. Applied Action outcomes, + Receipts, and decided-Tick WAL transactions retain the same projection, + bytes, type, and identity; fresh-host recovery revalidates them against the + installed package before publication. Rebound projections, mismatched + application inputs, and substituted result evidence fail closed. Obstructed + Actions carry no application result. The generic external runner reports and + recovers this evidence without a native application callback or + application-specific reconstruction. Runtime admission caps canonical + application input at 65,536 bytes and the compiler-declared result ceiling at + 65,536 before private scheduler evaluation. Both independent provider + components reject result ceilings above that runtime maximum and ambiguous + input bindings. Configuration-derived node-key and replacement field names + share the projection path-segment text ceiling. Package admission preserves + authored source kinds and paths, and optional result evidence carries an + explicit presence tag. Evaluation preflights exact canonical output size + before constructing the projected value, while recovery re-evaluates the + projection over the retained invocation input and refuses substituted result + bytes before publication. - The generic Edict-operation runner's duplicate witness now exposes canonical before/after application-state roots and typed target-value digests. The graph-only roots commit reachable application state without conflating WAL, @@ -30,11 +52,12 @@ closure, selects target configuration only from the package-supported target intrinsic, and verifies both created node and attachment types. The machine-readable witness reports exact package, verification-report, and - lawpack-manifest digests plus basis, node, submission, Tick-commit, and typed - Receipt identities. The checked external fixture and bounded failure/stress - suite contain application vocabulary only under `xtask/tests`; the - production runner is generic and contains no native application callback or - handwritten package. + lawpack-manifest digests plus basis, node, submission, Tick-commit, typed + Receipt, result-projection, output-type, canonical-result, and result + identities. The checked external fixture and bounded failure/stress suite + contain application vocabulary only under `xtask/tests`; the production + runner is generic and contains no native application callback or handwritten + package. - The former native `hello-echo` counter capsule is now explicitly named `runtime-counter-diagnostic`, including its command, artifact paths, and internal identities. It remains a low-level callback-based maintenance @@ -48,19 +71,19 @@ the source-to-package relation and emits an exact accepted or rejected `echo.operation-package-verifier-report/v1`. Target IR validation consumes the adapter-lowered target obstruction coordinate while independently - corroborating its source-failure mapping. The provider package exposes six - new closure domains through 30 total schema bindings. The generic route now + corroborating its source-failure mapping. The provider package exposes seven + new closure domains through 31 total schema bindings. The generic route now binds source-local capability aliases to canonical lawpack exports through the exact digest-locked Edict import and corroborates lawpack-owned coordinate-framed exports and adapter references independently from their provider-envelope domains. Its lowerer and verifier components were independently reproduced in copy-only, mount-free designated `linux/amd64` - containers and promoted at 230,875 bytes / - `08277d4ba7d98e0b143c06c208abc306f133bda510caa5393da08aa490334a6e` - and 248,221 bytes / - `744a511137608634b88abf7bd7e61da9bf81a5cacff7b190fc2530c346ba36cc`, + containers and promoted at 258,787 bytes / + `dfd14015705ff555a7efdb3787ddb0f8b4f304168a9a0ebf324fd25d430bf5cd` + and 277,836 bytes / + `279738ffeea40027eb493c15e873b87cf3aa0677a57f9f03fb824698e532322f`, respectively. The resulting 25-file package has provider identity - `sha256:a7ab6bfbbedc3a6b61a8559dc6506cfc3d2836b46dac3cc825e5b05b16b94fa5`. + `sha256:fe1a1f1c05e88bb3caeadb2d77fb17a906a4819674c50d75b2dcaca0fb6058ec`. This package build proves generic compiler/provider lowering and independent verification. The separate `run-edict-operation` witness now consumes that crossing through Echo-owned runtime execution. @@ -262,8 +285,8 @@ - `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 30 schema bindings—nine compatibility invocation domains, - the generated artifact profile, 14 generated-resource domains, and six + exact routes and 31 schema bindings—nine compatibility invocation domains, + the generated artifact profile, 14 generated-resource domains, and seven generic executable-operation closure 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 @@ -455,7 +478,8 @@ operations as bounded observers rather than mutation DPOs. These artifacts describe provider semantics and confer no Echo runtime authority. - `echo-wesley-gen` now admits the exact Apache-2.0 Edict provider contract - pack merged in Edict PR #162 as an explicit generator input. The pure + pack introduced in Edict PR #162 and extended with the result-projection + contract in Edict PR #174 as an explicit generator input. The pure boundary pins the CDDL and manifest publication, verifies strict contract and domain inventories plus every embedded resource byte, digest, and provenance record, rejects tampering with stable structured error kinds, and performs no diff --git a/Cargo.lock b/Cargo.lock index 585e918f..4f4d3d33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2218,6 +2218,7 @@ dependencies = [ "hex", "proptest", "rustc-hash 2.1.1", + "sha2", "thiserror 1.0.69", "warp-math", ] diff --git a/README.md b/README.md index 52a6b5ec..f400a862 100644 --- a/README.md +++ b/README.md @@ -255,14 +255,17 @@ external compiler-produced ExecutableOperationPackageV1 bytes -> exact manifest, target-adapter, and target-configuration closure -> Echo-owned package and invocation admission -> installed data-only EchoOperationProgramV1 +-> exact compiler-owned application-result projection +-> exact canonical application input retained in the invocation -> canonical Action submission retained before acknowledgement -> fresh-host package and pending-Action recovery -> runtime-owned admission into the ordinary head inbox -> scheduler selection at one exact basis -> bounded private Echo evaluation during Tick construction +-> exact typed application-result bytes and identity -> one composite Tick consequence with typed per-Action outcomes -> decided Tick WAL retention before state, frontier, and Receipt publication --> callback-free pending-Action and decided-Tick recovery +-> callback-free pending-Action, result, and decided-Tick recovery ``` The first two paths are callback-shaped compatibility infrastructure. The @@ -278,7 +281,16 @@ Tick. Its duplicate report exposes equal before/after application-state roots and typed target-value digests; the roots commit the reachable graph state, not WAL, history, Receipt, or commit metadata. It does not claim external multi-Action Tick composition, a product-ready application runner, a Jedit -operation, or a Graft operation. +operation, or a Graft operation. The same schema-neutral report exposes the +compiler-owned projection identity, output type coordinate, exact canonical +result bytes, and domain-separated result identity. A second fresh host must +recover byte-identical result evidence from the decided-Tick WAL; Echo does not +invoke a native application callback or reconstruct the result from target +state. +Canonical projected invocation input is capped at 65,536 bytes, and the +compiler-declared maximum result size is capped at 65,536 before private +scheduler evaluation. Produced canonical result bytes are measured against that +declared ceiling during evaluation. ## Contracts And Boundaries diff --git a/crates/echo-edict-provider-lowerer/README.md b/crates/echo-edict-provider-lowerer/README.md index b2e0461f..360562dd 100644 --- a/crates/echo-edict-provider-lowerer/README.md +++ b/crates/echo-edict-provider-lowerer/README.md @@ -45,10 +45,13 @@ exact digest-bound source, Core, lawpack, lawpack-exports, target-adapter, target-configuration, and Target IR artifacts. It derives the operation coordinate from the authored Core package and intent, validates the complete portable capability closure, and emits canonical `echo.operation-package/v1` -bytes for Echo's bounded anchored create-if-absent profile. Both the effect and -obstruction coordinates are resolved from source-local aliases through the -exact digest-locked lawpack import, so the package retains stable -lawpack-qualified identities. Application +bytes for Echo's bounded anchored create-if-absent profile. The route also +consumes the exact compiler-owned `edict.result-projection.artifact/v1`, +validates its operation, output type, bounded expression, and application-input +paths against Core and Target IR, and binds it into the package without +evaluating it. Both the effect and obstruction coordinates are resolved from +source-local aliases through the exact digest-locked lawpack import, so the +package retains stable lawpack-qualified identities. Application coordinates, intent names, effect names, failure names, type profiles, and authority profiles remain opaque artifact data; production lowering contains no application-specific dispatch or native callback. @@ -114,8 +117,8 @@ proposal constructor supports mutations and refuses a `Query`; authored reads remain a separate bounded observer/optic path and must never be represented as synthetic mutations. -The refreshed 230,875-byte checked lowerer component has SHA-256 -`08277d4ba7d98e0b143c06c208abc306f133bda510caa5393da08aa490334a6e` and has +The refreshed 258,787-byte checked lowerer component has SHA-256 +`dfd14015705ff555a7efdb3787ddb0f8b4f304168a9a0ebf324fd25d430bf5cd` and has crossed the reproducible promotion boundary. The pinned Edict host admits its generated envelope under the owning `generated-artifact` CDDL root, and the isolated host fixture exercises the exact helper binding, typed codecs, EINT diff --git a/crates/echo-edict-provider-lowerer/src/executable_operation.rs b/crates/echo-edict-provider-lowerer/src/executable_operation.rs index eb75cd23..e29d31f7 100644 --- a/crates/echo-edict-provider-lowerer/src/executable_operation.rs +++ b/crates/echo-edict-provider-lowerer/src/executable_operation.rs @@ -2,6 +2,8 @@ // © James Ross Ω FLYING•ROBOTS //! Generic data-only lowering into Echo's bounded executable-operation profile. +use std::collections::BTreeSet; + use blake3::Hasher; use echo_edict_canonical::{ digest_canonical_value_bytes_v1, encode_canonical_cbor_v1, CanonicalValueV1, @@ -26,6 +28,8 @@ const CONFIGURATION_ABI: &str = "echo.operation-lowering-configuration/v1"; const TARGET_IR_DOMAIN: &str = "edict.target-ir.artifact/v1"; const TARGET_IR_COORDINATE: &str = "echo.span-ir/v1"; const TARGET_IR_PAYLOAD_DOMAIN: &str = "echo.span-ir/v1"; +const RESULT_PROJECTION_DOMAIN: &str = "edict.result-projection.artifact/v1"; +const RESULT_PROJECTION_ABI: &str = "edict.result-projection/v1"; const PACKAGE_DOMAIN: &str = "echo.operation-package/v1"; const PACKAGE_ROLE: &str = "executable-operation-package.echo"; @@ -50,6 +54,11 @@ const EVALUATION_BASIS_SCHEMA: &str = "echo.operation.evaluation-basis/v1"; const FOOTPRINT_CONTRACT: &str = "anchored-node-alpha-create-if-absent-exact/v1"; const TARGET_PROFILE: &str = "echo.operation-target.anchored-node-alpha-create-if-absent/v1"; const PRECONDITION_MISMATCH: &str = "echo.executable-operation/precondition-mismatch/v1"; +const MAX_RESULT_PROJECTION_NODES: usize = 256; +const MAX_RESULT_PROJECTION_PATH_SEGMENTS: usize = 32; +const MAX_RESULT_PROJECTION_TEXT_BYTES: usize = 1_024; +const MAX_RESULT_PROJECTION_ARTIFACT_BYTES: usize = 64 * 1_024; +const MAX_APPLICATION_RESULT_BYTES: u64 = 64 * 1_024; #[derive(Clone, Copy)] struct ProgramConfiguration<'a> { @@ -60,6 +69,8 @@ struct ProgramConfiguration<'a> { steps: u64, read_bytes: u64, write_bytes: u64, + node_key_field: &'a str, + replacement_field: &'a str, } struct ApplicationIntent<'a> { @@ -76,9 +87,16 @@ struct ClosureInputs<'a> { lawpack: &'a SemanticInput, source: &'a SemanticInput, configuration: &'a SemanticInput, + result_projection: &'a SemanticInput, target_ir: &'a SemanticInput, } +struct ResultProjectionPlan { + runtime_expression: CanonicalValueV1, + node_key_path: Vec, + replacement_path: Vec, +} + pub(super) fn is_requested(request: &LoweringRequestV1) -> bool { request .requested_outputs @@ -97,6 +115,10 @@ pub(super) fn lower(request: &LoweringRequestV1) -> Result Result Result ProviderRefusalV1 { } fn select_closure(inputs: &[SemanticInput]) -> Result, ProviderRefusalV1> { - if inputs.len() != 6 { + if inputs.len() != 7 { return Err(super::unsupported_semantics( "semantic-inputs.echo-operation", )); @@ -192,6 +222,10 @@ fn select_closure(inputs: &[SemanticInput]) -> Result, Provide inputs, &SemanticInputKind::Auxiliary("target-configuration".to_owned()), )?, + result_projection: unique_input( + inputs, + &SemanticInputKind::Auxiliary("result-projection".to_owned()), + )?, target_ir: unique_input( inputs, &SemanticInputKind::Auxiliary("target-ir".to_owned()), @@ -503,18 +537,19 @@ fn validate_configuration( "invocationBinding", "target-configuration.echo-operation", )?; - if required_text( + let node_key_field = required_nonempty_text( invocation, "nodeKeyField", "target-configuration.echo-operation", - )? - .is_empty() - || required_text( - invocation, - "replacementField", - "target-configuration.echo-operation", - )? - .is_empty() + )?; + let replacement_field = required_nonempty_text( + invocation, + "replacementField", + "target-configuration.echo-operation", + )?; + validate_projection_text(node_key_field, "target-configuration.echo-operation")?; + validate_projection_text(replacement_field, "target-configuration.echo-operation")?; + if node_key_field == replacement_field || text_field(invocation, "nodeIdDerivation") != Some("sha256-utf8/v1") || text_field(invocation, "warpIdSource") != Some("action-lane/v1") { @@ -551,6 +586,8 @@ fn validate_configuration( steps: required_u64(budget, "steps", "target-configuration.echo-operation")?, read_bytes: required_u64(budget, "readBytes", "target-configuration.echo-operation")?, write_bytes: required_u64(budget, "writeBytes", "target-configuration.echo-operation")?, + node_key_field, + replacement_field, }; if configuration.max_replacement_bytes == 0 || configuration.steps < 3 @@ -564,12 +601,250 @@ fn validate_configuration( Ok(configuration) } +fn validate_result_projection( + value: &CanonicalValueV1, + input: &SemanticInput, + target_ir: &CanonicalValueV1, + intent: &ApplicationIntent<'_>, + configuration: ProgramConfiguration<'_>, +) -> Result { + if input.artifact.artifact.bytes.len() > MAX_RESULT_PROJECTION_ARTIFACT_BYTES { + return Err(invalid_artifact( + &input.role, + "result projection exceeds the canonical byte bound", + )); + } + require_exact_fields( + value, + &[ + "expression", + "maxOutputBytes", + "operationCoordinate", + "outputType", + "schema", + ], + &input.role, + )?; + if text_field(value, "schema") != Some(RESULT_PROJECTION_ABI) + || text_field(value, "operationCoordinate") != Some(intent.operation_coordinate.as_str()) + || input.artifact.reference.coordinate != intent.operation_coordinate + { + return Err(invalid_artifact( + &input.role, + "result projection is rebound from the application operation", + )); + } + validate_projection_text( + required_nonempty_text(value, "outputType", &input.role)?, + &input.role, + )?; + let max_output_bytes = required_u64(value, "maxOutputBytes", &input.role)?; + if max_output_bytes == 0 || max_output_bytes > MAX_APPLICATION_RESULT_BYTES { + return Err(invalid_artifact( + &input.role, + "result projection output bound is outside the Echo runtime ceiling", + )); + } + let target_intents = required_map(target_ir, "intents", &input.role)?; + let target_intent = required_map_field( + target_intents, + intent.name, + "result-projection.target-intent", + )?; + let [target_step] = required_array(target_intent, "steps", &input.role)?.as_slice() else { + return Err(super::unsupported_semantics( + "result-projection.target-steps", + )); + }; + let target_step_id = required_nonempty_text(target_step, "id", &input.role)?; + let mut nodes = 0; + let runtime_expression = lower_projection_expression( + required_map(value, "expression", &input.role)?, + target_step_id, + configuration.node_key_field, + &mut nodes, + &input.role, + )?; + Ok(ResultProjectionPlan { + runtime_expression, + node_key_path: vec![configuration.node_key_field.to_owned()], + replacement_path: vec![configuration.replacement_field.to_owned()], + }) +} + +fn lower_projection_expression( + value: &CanonicalValueV1, + target_step_id: &str, + node_key_field: &str, + nodes: &mut usize, + subject: &str, +) -> Result { + *nodes = nodes + .checked_add(1) + .ok_or_else(|| invalid_artifact(subject, "result projection node count overflowed"))?; + if *nodes > MAX_RESULT_PROJECTION_NODES { + return Err(invalid_artifact( + subject, + "result projection exceeds the expression-node bound", + )); + } + let kind = required_text(value, "kind", subject)?; + match kind { + "record" => { + require_exact_fields(value, &["fields", "kind"], subject)?; + let fields = required_map(value, "fields", subject)?; + let entries = as_map(fields) + .ok_or_else(|| invalid_artifact(subject, "projection fields must be a map"))?; + let mut lowered = Vec::with_capacity(entries.len()); + for (name, expression) in entries { + let Some(name) = as_text(name) else { + return Err(invalid_artifact( + subject, + "projection field names must be text", + )); + }; + validate_projection_text(name, subject)?; + lowered.push(( + name.to_owned(), + lower_projection_expression( + expression, + target_step_id, + node_key_field, + nodes, + subject, + )?, + )); + } + Ok(canonical_map([ + ("kind", canonical_text("record")), + ( + "fields", + CanonicalValueV1::Map( + lowered + .into_iter() + .map(|(name, value)| (canonical_text(&name), value)) + .collect(), + ), + ), + ])) + } + "source" => { + require_exact_fields(value, &["kind", "path", "source"], subject)?; + let source = required_map(value, "source", subject)?; + let source_kind = required_text(source, "kind", subject)?; + let path = required_array(value, "path", subject)?; + if path.len() > MAX_RESULT_PROJECTION_PATH_SEGMENTS { + return Err(invalid_artifact( + subject, + "result projection path exceeds the segment bound", + )); + } + let mut lowered_path = Vec::with_capacity(path.len()); + for segment in path { + let Some(segment) = as_text(segment) else { + return Err(invalid_artifact( + subject, + "result projection path segment must be text", + )); + }; + validate_projection_text(segment, subject)?; + lowered_path.push(segment.to_owned()); + } + match source_kind { + "applicationInput" => { + require_exact_fields(source, &["kind"], subject)?; + } + "capabilityResult" => { + require_exact_fields(source, &["kind", "stepId"], subject)?; + if required_text(source, "stepId", subject)? != target_step_id + || lowered_path != [node_key_field] + { + return Err(super::unsupported_semantics( + "result-projection.capability-result", + )); + } + lowered_path = vec![node_key_field.to_owned()]; + } + _ => { + return Err(invalid_artifact( + subject, + "result projection names an unsupported source kind", + )); + } + } + Ok(canonical_map([ + ("kind", canonical_text("source")), + ( + "path", + CanonicalValueV1::Array( + lowered_path + .into_iter() + .map(|segment| canonical_text(&segment)) + .collect(), + ), + ), + ( + "source", + canonical_map([("kind", canonical_text("applicationInput"))]), + ), + ])) + } + _ => Err(invalid_artifact( + subject, + "result projection names an unsupported expression kind", + )), + } +} + +fn require_exact_fields( + value: &CanonicalValueV1, + expected: &[&str], + subject: &str, +) -> Result<(), ProviderRefusalV1> { + let entries = as_map(value) + .ok_or_else(|| invalid_artifact(subject, "result projection node must be a map"))?; + let mut actual = BTreeSet::new(); + for (key, _) in entries { + let Some(key) = as_text(key) else { + return Err(invalid_artifact( + subject, + "result projection map key must be text", + )); + }; + if !actual.insert(key) { + return Err(invalid_artifact( + subject, + "result projection repeats a map field", + )); + } + } + let expected = expected.iter().copied().collect::>(); + if actual != expected { + return Err(invalid_artifact( + subject, + "result projection has an unexpected field set", + )); + } + Ok(()) +} + +fn validate_projection_text(value: &str, subject: &str) -> Result<(), ProviderRefusalV1> { + if value.is_empty() || value.len() > MAX_RESULT_PROJECTION_TEXT_BYTES { + return Err(invalid_artifact( + subject, + "result projection text is empty or exceeds its byte bound", + )); + } + Ok(()) +} + fn encode_package( request: &LoweringRequestV1, closure: &ClosureInputs<'_>, intent: &ApplicationIntent<'_>, obstruction_coordinate: &str, configuration: ProgramConfiguration<'_>, + result_projection: &ResultProjectionPlan, ) -> Result, ProviderRefusalV1> { let program = canonical_map([ ( @@ -633,6 +908,45 @@ fn encode_package( ), ]); let package = canonical_map([ + ( + "application_result_projection", + canonical_map([ + ( + "application_input_node_key_path", + CanonicalValueV1::Array( + result_projection + .node_key_path + .iter() + .map(|segment| canonical_text(segment)) + .collect(), + ), + ), + ( + "application_input_replacement_path", + CanonicalValueV1::Array( + result_projection + .replacement_path + .iter() + .map(|segment| canonical_text(segment)) + .collect(), + ), + ), + ( + "artifact_bytes", + CanonicalValueV1::Bytes( + closure.result_projection.artifact.artifact.bytes.clone(), + ), + ), + ( + "artifact_identity", + hash_value(hash_from_bound(&closure.result_projection.artifact)?), + ), + ( + "runtime_expression", + result_projection.runtime_expression.clone(), + ), + ]), + ), ( "application_basis_schema_identity", hash_value(profile_digest(APPLICATION_BASIS_SCHEMA)), diff --git a/crates/echo-edict-provider-lowerer/src/lib.rs b/crates/echo-edict-provider-lowerer/src/lib.rs index c801cf14..c3dd6a8c 100644 --- a/crates/echo-edict-provider-lowerer/src/lib.rs +++ b/crates/echo-edict-provider-lowerer/src/lib.rs @@ -809,7 +809,7 @@ pub mod echo_dpo { pub const PROVIDER_SCHEMA_COORDINATE: &str = "echo.provider-artifacts.cddl@1"; /// Raw SHA-256 of the exact self-contained provider CDDL bytes. pub const PROVIDER_SCHEMA_SHA256_HEX: &str = - "6b9076ae02730797fddf60a93606df3de245a1c6bfbd845486799b7310d002a2"; + "730ce72f6658fe8cc9302221c32ad5992492e190674ddd69c1b164749d2bb669"; /// Exact generated-artifact profile coordinate owning operation schemas. pub const GENERATED_ARTIFACT_PROFILE: &str = "echo.dpo.registration/v1"; /// Digest-framing domain for the generated-artifact profile. @@ -846,7 +846,7 @@ pub mod echo_dpo { const MUTATION_RULE_NAME: &str = concat!( "cmd/contract/", - "6b9076ae02730797fddf60a93606df3de245a1c6bfbd845486799b7310d002a2", + "730ce72f6658fe8cc9302221c32ad5992492e190674ddd69c1b164749d2bb669", "/3389142194/a.b@1.t" ); const PROVIDER_OPERATIONS: [ProviderOperationV1<'static>; 1] = [ProviderOperationV1 { diff --git a/crates/echo-edict-provider-lowerer/tests/executable_operation_package.rs b/crates/echo-edict-provider-lowerer/tests/executable_operation_package.rs index 6e967027..fb9b8d96 100644 --- a/crates/echo-edict-provider-lowerer/tests/executable_operation_package.rs +++ b/crates/echo-edict-provider-lowerer/tests/executable_operation_package.rs @@ -21,6 +21,7 @@ use warp_core::{ const TARGET_PROFILE: &[u8] = include_bytes!("../resources/target-profile.echo-dpo.cbor"); const PACKAGE_ROLE: &str = "executable-operation-package.echo"; const PACKAGE_DOMAIN: &str = "echo.operation-package/v1"; +const RESULT_PROJECTION_DOMAIN: &str = "edict.result-projection.artifact/v1"; const TARGET_INTRINSIC: &str = "echo.dpo@1.anchored-node-attachment-create-if-absent"; const PRECONDITION_MISMATCH: &str = "echo.executable-operation/precondition-mismatch/v1"; @@ -149,7 +150,227 @@ fn semantic_roles_do_not_encode_application_names() { assert_eq!(success.outputs.len(), 1); } +#[test] +fn compiler_result_projection_is_bound_into_the_package_exactly() { + let request = fixture_request(ALPHA); + let projection = request + .semantic_inputs + .iter() + .find(|input| input.kind == SemanticInputKind::Auxiliary("result-projection".to_owned())) + .expect("fixture carries the compiler result projection") + .clone(); + let expected_identity = hash(&projection.artifact.reference.digest); + let expected_bytes = projection.artifact.artifact.bytes; + + let success = lower(request).expect("the projection-bearing closure lowers"); + let package = decode_canonical_cbor_v1(&success.outputs[0].artifact.bytes) + .expect("the emitted package is canonical"); + let bound_projection = map_value(&package, "application_result_projection"); + + assert_eq!( + bytes_slice(bound_projection, "artifact_bytes"), + expected_bytes.as_slice() + ); + assert_eq!( + bytes_value::<32>(bound_projection, "artifact_identity"), + expected_identity + ); +} + +#[test] +fn result_projection_is_a_mandatory_semantic_input() { + let mut request = fixture_request(ALPHA); + request + .semantic_inputs + .retain(|input| input.kind != SemanticInputKind::Auxiliary("result-projection".to_owned())); + + let refusal = lower(request).expect_err("a six-input closure must fail closed"); + + assert_eq!( + refusal.kind, + echo_edict_provider_lowerer::ProviderRefusalKind::UnsupportedSemantics + ); +} + +#[test] +fn rebound_result_projection_coordinate_is_an_invalid_artifact() { + let mut request = fixture_request(ALPHA); + let projection = request + .semantic_inputs + .iter_mut() + .find(|input| input.kind == SemanticInputKind::Auxiliary("result-projection".to_owned())) + .expect("fixture carries the compiler result projection"); + projection.artifact.reference.coordinate = "forged.application@9.otherResult".to_owned(); + + let refusal = lower(request).expect_err("a rebound projection must fail closed"); + + assert_eq!( + refusal.kind, + echo_edict_provider_lowerer::ProviderRefusalKind::InvalidSemanticArtifact + ); +} + +#[test] +fn projection_output_ceiling_accepts_the_boundary_and_rejects_the_next_byte() { + let mut boundary = fixture_request(ALPHA); + replace_projection( + &mut boundary, + result_projection_with_max_output(ALPHA, 65_536), + ); + lower(boundary).expect("the Echo runtime output ceiling is accepted"); + + let mut over_limit = fixture_request(ALPHA); + replace_projection( + &mut over_limit, + result_projection_with_max_output(ALPHA, 65_537), + ); + let refusal = + lower(over_limit).expect_err("a package above Echo's output ceiling must fail closed"); + assert_eq!( + refusal.kind, + echo_edict_provider_lowerer::ProviderRefusalKind::InvalidSemanticArtifact + ); +} + +#[test] +fn invocation_binding_fields_must_be_distinct() { + let request = + fixture_request_with_configuration(ALPHA, configuration_with_fields(ALPHA, "key", "key")); + + let refusal = + lower(request).expect_err("one input field cannot bind two distinct runtime values"); + + assert_eq!( + refusal.kind, + echo_edict_provider_lowerer::ProviderRefusalKind::UnsupportedSemantics + ); +} + +#[test] +fn invocation_binding_field_length_accepts_the_boundary_and_rejects_the_next_byte() { + let boundary = "x".repeat(1_024); + for (node_key_field, replacement_field) in + [(boundary.as_str(), "value"), ("key", boundary.as_str())] + { + let mut request = fixture_request_with_configuration( + ALPHA, + configuration_with_fields(ALPHA, node_key_field, replacement_field), + ); + replace_projection( + &mut request, + result_projection_with_binding_fields(ALPHA, node_key_field, replacement_field), + ); + lower(request).expect("the exact invocation-binding field boundary is accepted"); + } + + let over_limit = "x".repeat(1_025); + for (node_key_field, replacement_field) in + [(over_limit.as_str(), "value"), ("key", over_limit.as_str())] + { + let request = fixture_request_with_configuration( + ALPHA, + configuration_with_fields(ALPHA, node_key_field, replacement_field), + ); + let refusal = + lower(request).expect_err("an oversized invocation-binding field must fail closed"); + assert_eq!( + refusal.kind, + echo_edict_provider_lowerer::ProviderRefusalKind::InvalidSemanticArtifact + ); + } +} + +#[test] +fn projection_node_limit_accepts_the_boundary_and_rejects_the_next_node() { + let mut boundary = fixture_request(ALPHA); + replace_projection(&mut boundary, result_projection_with_fields(ALPHA, 255)); + lower(boundary).expect("one root plus 255 source leaves is the exact boundary"); + + let mut over_limit = fixture_request(ALPHA); + replace_projection(&mut over_limit, result_projection_with_fields(ALPHA, 256)); + let refusal = lower(over_limit).expect_err("the 257th projection node must fail closed"); + assert_eq!( + refusal.kind, + echo_edict_provider_lowerer::ProviderRefusalKind::InvalidSemanticArtifact + ); +} + +#[test] +fn repeated_projection_lowering_is_stable_under_bounded_stress() { + let expected = lower(fixture_request(ALPHA)) + .expect("the first projection-bearing closure lowers") + .outputs[0] + .artifact + .bytes + .clone(); + + for iteration in 0..128 { + let actual = lower(fixture_request(ALPHA)) + .unwrap_or_else(|error| panic!("iteration {iteration} refused: {error:?}")) + .outputs[0] + .artifact + .bytes + .clone(); + assert_eq!( + actual, expected, + "iteration {iteration} changed package bytes" + ); + } +} + +#[test] +fn projection_field_order_is_canonical_for_fixed_seed_permutations() { + const SEED: u64 = 0x0698_5eed_cafe_babe; + let field_names = ["alpha", "beta", "delta", "gamma"]; + let mut expected_request = fixture_request(ALPHA); + replace_projection( + &mut expected_request, + result_projection_with_field_order(ALPHA, &field_names), + ); + let expected = lower(expected_request) + .expect("the canonical field order lowers") + .outputs[0] + .artifact + .bytes + .clone(); + let mut state = SEED; + + for case in 0..64 { + let mut permutation = field_names; + for index in (1..permutation.len()).rev() { + state ^= state << 13; + state ^= state >> 7; + state ^= state << 17; + let swap = usize::try_from(state % u64::try_from(index + 1).expect("small bound")) + .expect("small index"); + permutation.swap(index, swap); + } + let mut request = fixture_request(ALPHA); + replace_projection( + &mut request, + result_projection_with_field_order(ALPHA, &permutation), + ); + let actual = lower(request) + .unwrap_or_else(|error| panic!("seed {SEED:#x}, case {case} refused: {error:?}")) + .outputs[0] + .artifact + .bytes + .clone(); + assert_eq!( + actual, expected, + "seed {SEED:#x}, case {case} changed package bytes" + ); + } +} + fn fixture_request(names: FixtureNames<'_>) -> LoweringRequestV1 { + fixture_request_with_configuration(names, configuration(names)) +} + +fn fixture_request_with_configuration( + names: FixtureNames<'_>, + configuration_value: CanonicalValueV1, +) -> LoweringRequestV1 { let target_profile = bound( "echo.dpo@1", "edict.target-profile/v1", @@ -163,7 +384,7 @@ fn fixture_request(names: FixtureNames<'_>) -> LoweringRequestV1 { let configuration = bound( names.configuration, "echo.operation-lowering-configuration/v1", - canonical_bytes(&configuration(names)), + canonical_bytes(&configuration_value), ); let adapter = bound( names.adapter, @@ -201,6 +422,11 @@ fn fixture_request(names: FixtureNames<'_>) -> LoweringRequestV1 { "edict.target-ir.artifact/v1", canonical_bytes(&target_ir(names, &core, &lawpack, &target_profile)), ); + let result_projection = bound( + &format!("{}.{}", names.application, names.intent), + RESULT_PROJECTION_DOMAIN, + canonical_bytes(&result_projection(names)), + ); LoweringRequestV1 { protocol_version: ProtocolVersionV1 { @@ -237,6 +463,11 @@ fn fixture_request(names: FixtureNames<'_>) -> LoweringRequestV1 { SemanticInputKind::Auxiliary("target-ir".to_owned()), target_ir, ), + semantic_input( + "result-projection", + SemanticInputKind::Auxiliary("result-projection".to_owned()), + result_projection, + ), ], requested_outputs: vec![LoweringOutputRequest { role: PACKAGE_ROLE.to_owned(), @@ -333,6 +564,14 @@ fn exports(names: FixtureNames<'_>) -> CanonicalValueV1 { } fn configuration(names: FixtureNames<'_>) -> CanonicalValueV1 { + configuration_with_fields(names, "key", "value") +} + +fn configuration_with_fields( + names: FixtureNames<'_>, + node_key_field: &str, + replacement_field: &str, +) -> CanonicalValueV1 { owned_map([ ( "apiVersion", @@ -357,8 +596,8 @@ fn configuration(names: FixtureNames<'_>) -> CanonicalValueV1 { ( "invocationBinding", owned_map([ - ("nodeKeyField", text("key")), - ("replacementField", text("value")), + ("nodeKeyField", text(node_key_field)), + ("replacementField", text(replacement_field)), ("nodeIdDerivation", text("sha256-utf8/v1")), ("warpIdSource", text("action-lane/v1")), ]), @@ -462,6 +701,7 @@ fn target_ir( ( "steps", CanonicalValueV1::Array(vec![owned_map([ + ("id", text("step.0")), ("targetIntrinsic", text(TARGET_INTRINSIC)), ( "obstructionFailures", @@ -475,6 +715,189 @@ fn target_ir( ]) } +fn result_projection(names: FixtureNames<'_>) -> CanonicalValueV1 { + result_projection_with_max_output(names, 512) +} + +fn result_projection_with_max_output( + names: FixtureNames<'_>, + max_output_bytes: u64, +) -> CanonicalValueV1 { + result_projection_with_binding_fields_and_max_output(names, "key", "value", max_output_bytes) +} + +fn result_projection_with_binding_fields( + names: FixtureNames<'_>, + node_key_field: &str, + replacement_field: &str, +) -> CanonicalValueV1 { + result_projection_with_binding_fields_and_max_output( + names, + node_key_field, + replacement_field, + 512, + ) +} + +fn result_projection_with_binding_fields_and_max_output( + names: FixtureNames<'_>, + node_key_field: &str, + replacement_field: &str, + max_output_bytes: u64, +) -> CanonicalValueV1 { + owned_map([ + ("schema", text("edict.result-projection/v1")), + ( + "operationCoordinate", + text(format!("{}.{}", names.application, names.intent)), + ), + ("outputType", text(format!("{}.Output", names.application))), + ("maxOutputBytes", integer(max_output_bytes)), + ( + "expression", + owned_map([ + ("kind", text("record")), + ( + "fields", + dynamic_map([ + ( + "first", + projection_source( + owned_map([ + ("kind", text("capabilityResult")), + ("stepId", text("step.0")), + ]), + [node_key_field], + ), + ), + ( + "second", + projection_source( + owned_map([("kind", text("applicationInput"))]), + [replacement_field], + ), + ), + ]), + ), + ]), + ), + ]) +} + +fn runtime_result_expression() -> CanonicalValueV1 { + owned_map([ + ("kind", text("record")), + ( + "fields", + dynamic_map([ + ( + "first", + projection_source(owned_map([("kind", text("applicationInput"))]), ["key"]), + ), + ( + "second", + projection_source(owned_map([("kind", text("applicationInput"))]), ["value"]), + ), + ]), + ), + ]) +} + +fn result_projection_with_fields(names: FixtureNames<'_>, field_count: usize) -> CanonicalValueV1 { + let fields = (0..field_count) + .map(|index| { + ( + format!("field-{index:03}"), + projection_source(owned_map([("kind", text("applicationInput"))]), ["value"]), + ) + }) + .collect::>(); + owned_map([ + ("schema", text("edict.result-projection/v1")), + ( + "operationCoordinate", + text(format!("{}.{}", names.application, names.intent)), + ), + ("outputType", text(format!("{}.Output", names.application))), + ("maxOutputBytes", integer(65_536)), + ( + "expression", + owned_map([ + ("kind", text("record")), + ( + "fields", + dynamic_map( + fields + .iter() + .map(|(name, expression)| (name.as_str(), expression.clone())), + ), + ), + ]), + ), + ]) +} + +fn result_projection_with_field_order( + names: FixtureNames<'_>, + field_names: &[&str], +) -> CanonicalValueV1 { + owned_map([ + ("schema", text("edict.result-projection/v1")), + ( + "operationCoordinate", + text(format!("{}.{}", names.application, names.intent)), + ), + ("outputType", text(format!("{}.Output", names.application))), + ("maxOutputBytes", integer(512)), + ( + "expression", + owned_map([ + ("kind", text("record")), + ( + "fields", + dynamic_map(field_names.iter().map(|name| { + ( + *name, + projection_source( + owned_map([("kind", text("applicationInput"))]), + ["value"], + ), + ) + })), + ), + ]), + ), + ]) +} + +fn projection_source( + source: CanonicalValueV1, + path: [&str; N], +) -> CanonicalValueV1 { + owned_map([ + ("kind", text("source")), + ("source", source), + ( + "path", + CanonicalValueV1::Array(path.into_iter().map(text).collect()), + ), + ]) +} + +fn replace_projection(request: &mut LoweringRequestV1, value: CanonicalValueV1) { + let input = request + .semantic_inputs + .iter_mut() + .find(|input| input.kind == SemanticInputKind::Auxiliary("result-projection".to_owned())) + .expect("fixture carries the compiler result projection"); + let coordinate = input.artifact.reference.coordinate.clone(); + input.artifact = bound( + &coordinate, + RESULT_PROJECTION_DOMAIN, + canonical_bytes(&value), + ); +} + fn expected_package( request: &LoweringRequestV1, names: FixtureNames<'_>, @@ -491,6 +914,9 @@ fn expected_package( let exports = input(&SemanticInputKind::Auxiliary("lawpack-exports".to_owned())); let lawpack = input(&SemanticInputKind::Lawpack); let target_ir = input(&SemanticInputKind::Auxiliary("target-ir".to_owned())); + let result_projection = input(&SemanticInputKind::Auxiliary( + "result-projection".to_owned(), + )); let core_identity = hash(&request.core.reference.digest); ExecutableOperationPackageV1::new( format!("{}.{}", names.application, names.intent), @@ -514,6 +940,14 @@ fn expected_package( 256, ), ) + .with_application_result_projection( + result_projection.artifact.bytes.clone(), + hash(&result_projection.reference.digest), + vec!["key".to_owned()], + vec!["value".to_owned()], + &canonical_bytes(&runtime_result_expression()), + ) + .expect("the independent package model accepts the fixture projection") } fn semantic_input(role: &str, kind: SemanticInputKind, artifact: BoundArtifact) -> SemanticInput { @@ -614,3 +1048,26 @@ fn text_field<'a>(value: &'a CanonicalValueV1, field: &str) -> Option<&'a str> { } }) } + +fn map_value<'a>(value: &'a CanonicalValueV1, field: &str) -> &'a CanonicalValueV1 { + let CanonicalValueV1::Map(entries) = value else { + panic!("expected canonical map"); + }; + entries + .iter() + .find_map(|(key, value)| (key == &text(field)).then_some(value)) + .unwrap_or_else(|| panic!("missing map field {field}")) +} + +fn bytes_value(value: &CanonicalValueV1, field: &str) -> [u8; N] { + bytes_slice(value, field) + .try_into() + .unwrap_or_else(|_| panic!("field {field} has the wrong byte length")) +} + +fn bytes_slice<'a>(value: &'a CanonicalValueV1, field: &str) -> &'a [u8] { + let CanonicalValueV1::Bytes(bytes) = map_value(value, field) else { + panic!("field {field} is not bytes"); + }; + bytes +} diff --git a/crates/echo-edict-provider-lowerer/tests/fixtures/generated_echo_dpo.rs b/crates/echo-edict-provider-lowerer/tests/fixtures/generated_echo_dpo.rs index 840ad5fd..7d1ecd65 100644 --- a/crates/echo-edict-provider-lowerer/tests/fixtures/generated_echo_dpo.rs +++ b/crates/echo-edict-provider-lowerer/tests/fixtures/generated_echo_dpo.rs @@ -71,7 +71,7 @@ pub mod echo_dpo { pub const PROVIDER_SCHEMA_COORDINATE: &str = "echo.provider-artifacts.cddl@1"; /// Raw SHA-256 of the exact self-contained provider CDDL bytes. pub const PROVIDER_SCHEMA_SHA256_HEX: &str = - "6b9076ae02730797fddf60a93606df3de245a1c6bfbd845486799b7310d002a2"; + "730ce72f6658fe8cc9302221c32ad5992492e190674ddd69c1b164749d2bb669"; /// Exact generated-artifact profile coordinate owning operation schemas. pub const GENERATED_ARTIFACT_PROFILE: &str = "echo.dpo.registration/v1"; /// Digest-framing domain for the generated-artifact profile. @@ -108,7 +108,7 @@ pub mod echo_dpo { const MUTATION_RULE_NAME: &str = concat!( "cmd/contract/", - "6b9076ae02730797fddf60a93606df3de245a1c6bfbd845486799b7310d002a2", + "730ce72f6658fe8cc9302221c32ad5992492e190674ddd69c1b164749d2bb669", "/3389142194/a.b@1.t" ); const PROVIDER_OPERATIONS: [ProviderOperationV1<'static>; 1] = [ProviderOperationV1 { diff --git a/crates/echo-edict-provider-lowerer/tests/lowerer_contract.rs b/crates/echo-edict-provider-lowerer/tests/lowerer_contract.rs index fffb1f42..b9777430 100644 --- a/crates/echo-edict-provider-lowerer/tests/lowerer_contract.rs +++ b/crates/echo-edict-provider-lowerer/tests/lowerer_contract.rs @@ -45,7 +45,7 @@ const REVIEW_MEDIA_TYPE: &str = "application/json"; const GENERATED_SOURCE_PATH: &str = "generated/echo_dpo.rs"; const REVIEW_PATH: &str = "review/echo_dpo.json"; const EXPECTED_PROVIDER_SCHEMA_SHA256_HEX: &str = - "6b9076ae02730797fddf60a93606df3de245a1c6bfbd845486799b7310d002a2"; + "730ce72f6658fe8cc9302221c32ad5992492e190674ddd69c1b164749d2bb669"; const EXPECTED_OPERATION_ID_LAW: &str = "echo.semantic-operation-id.fnv1-32/v1"; const EXPECTED_OPERATION_ID: u32 = 3_389_142_194; diff --git a/crates/echo-edict-provider-verifier/README.md b/crates/echo-edict-provider-verifier/README.md index 33aceab4..61cd38ae 100644 --- a/crates/echo-edict-provider-verifier/README.md +++ b/crates/echo-edict-provider-verifier/README.md @@ -28,14 +28,17 @@ the lowerer. Exact equality yields an accepted `echo.operation-package-verifier-report/v1`; a rebound or otherwise self-consistent package mutation yields a typed rejected report. The verifier independently resolves source-local effect and obstruction aliases through the -exact lawpack import before comparing the canonical package. Application -vocabulary is treated only as opaque authored data. +exact lawpack import before comparing the canonical package. It independently +validates the compiler-owned result-projection artifact, reconstructs the +runtime expression and application-input paths, binds their identity into the +expected package, and names that exact projection in the accepted report. +Application vocabulary is treated only as opaque authored data. 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 248,221-byte checked +transport-to-model conversion. Its reproducibly built 277,836-byte checked component has SHA-256 -`744a511137608634b88abf7bd7e61da9bf81a5cacff7b190fc2530c346ba36cc`. +`279738ffeea40027eb493c15e873b87cf3aa0677a57f9f03fb824698e532322f`. 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-edict-provider-verifier/src/executable_operation.rs b/crates/echo-edict-provider-verifier/src/executable_operation.rs index 7caa9763..c420bbd2 100644 --- a/crates/echo-edict-provider-verifier/src/executable_operation.rs +++ b/crates/echo-edict-provider-verifier/src/executable_operation.rs @@ -2,6 +2,8 @@ // © James Ross Ω FLYING•ROBOTS //! Independent verification for generic bounded executable-operation packages. +use std::collections::BTreeSet; + use blake3::Hasher; use echo_edict_canonical::{ digest_canonical_value_bytes_v1, encode_canonical_cbor_v1, CanonicalValueV1, @@ -27,6 +29,8 @@ const CONFIGURATION_ABI: &str = "echo.operation-lowering-configuration/v1"; const TARGET_IR_DOMAIN: &str = "edict.target-ir.artifact/v1"; const TARGET_IR_COORDINATE: &str = "echo.span-ir/v1"; const TARGET_IR_PAYLOAD_DOMAIN: &str = "echo.span-ir/v1"; +const RESULT_PROJECTION_DOMAIN: &str = "edict.result-projection.artifact/v1"; +const RESULT_PROJECTION_ABI: &str = "edict.result-projection/v1"; const PACKAGE_DOMAIN: &str = "echo.operation-package/v1"; const PACKAGE_COORDINATE: &str = "executable-operation-package.echo"; const REPORT_DOMAIN: &str = "echo.operation-package-verifier-report/v1"; @@ -54,6 +58,11 @@ const EVALUATION_BASIS_SCHEMA: &str = "echo.operation.evaluation-basis/v1"; const FOOTPRINT_CONTRACT: &str = "anchored-node-alpha-create-if-absent-exact/v1"; const TARGET_PROFILE: &str = "echo.operation-target.anchored-node-alpha-create-if-absent/v1"; const PRECONDITION_MISMATCH: &str = "echo.executable-operation/precondition-mismatch/v1"; +const MAX_RESULT_PROJECTION_NODES: usize = 256; +const MAX_RESULT_PROJECTION_PATH_SEGMENTS: usize = 32; +const MAX_RESULT_PROJECTION_TEXT_BYTES: usize = 1_024; +const MAX_RESULT_PROJECTION_ARTIFACT_BYTES: usize = 64 * 1_024; +const MAX_APPLICATION_RESULT_BYTES: u64 = 64 * 1_024; #[derive(Clone, Copy)] struct ProgramConfiguration<'a> { @@ -64,6 +73,8 @@ struct ProgramConfiguration<'a> { steps: u64, read_bytes: u64, write_bytes: u64, + node_key_field: &'a str, + replacement_field: &'a str, } struct ApplicationIntent<'a> { @@ -81,6 +92,13 @@ struct ClosureInputs<'a> { lawpack: &'a SemanticInput, source: &'a SemanticInput, configuration: &'a SemanticInput, + result_projection: &'a SemanticInput, +} + +struct ResultProjectionPlan { + runtime_expression: CanonicalValueV1, + node_key_path: Vec, + replacement_path: Vec, } pub(super) fn is_requested(request: &VerificationRequestV1) -> bool { @@ -109,6 +127,10 @@ pub(super) fn verify( let lawpack = validate_bound(&closure.lawpack.artifact, LAWPACK_DOMAIN)?; let source = validate_bound(&closure.source.artifact, SOURCE_DOMAIN)?; let configuration = validate_bound(&closure.configuration.artifact, CONFIGURATION_DOMAIN)?; + let result_projection = validate_bound( + &closure.result_projection.artifact, + RESULT_PROJECTION_DOMAIN, + )?; let source = validate_source(&source, closure.source, &request.core)?; let semantic_effect = @@ -128,12 +150,20 @@ pub(super) fn verify( validate_adapter(&adapter, closure.configuration, &intent, &semantic_effect)?; validate_target_ir(&target_ir, request, closure.lawpack, &intent)?; let configuration = validate_configuration(&configuration)?; + let result_projection = validate_result_projection( + &result_projection, + closure.result_projection, + &target_ir, + &intent, + configuration, + )?; let expected = encode_expected_package( request, &closure, &intent, &semantic_obstruction, configuration, + &result_projection, )?; let actual = encode_canonical_cbor_v1(&package) .map_err(|_| invalid_artifact(PACKAGE_COORDINATE, "package could not be re-encoded"))?; @@ -158,6 +188,7 @@ pub(super) fn verify( let report = build_report( &closure.package.artifact.reference, &request.target_ir.reference, + &closure.result_projection.artifact.reference, outcome, diagnostic_bytes, )?; @@ -199,7 +230,7 @@ fn unsupported_output(subject: &str) -> ProviderRefusalV1 { } fn select_closure(inputs: &[SemanticInput]) -> Result, ProviderRefusalV1> { - if inputs.len() != 6 { + if inputs.len() != 7 { return Err(super::unsupported_semantics( "semantic-inputs.echo-operation", )); @@ -226,6 +257,10 @@ fn select_closure(inputs: &[SemanticInput]) -> Result, Provide inputs, &SemanticInputKind::Auxiliary("target-configuration".to_owned()), )?, + result_projection: unique_input( + inputs, + &SemanticInputKind::Auxiliary("result-projection".to_owned()), + )?, }) } @@ -539,18 +574,19 @@ fn validate_configuration( "invocationBinding", "target-configuration.echo-operation", )?; - if required_nonempty_text( + let node_key_field = required_nonempty_text( invocation, "nodeKeyField", "target-configuration.echo-operation", - )? - .is_empty() - || required_nonempty_text( - invocation, - "replacementField", - "target-configuration.echo-operation", - )? - .is_empty() + )?; + let replacement_field = required_nonempty_text( + invocation, + "replacementField", + "target-configuration.echo-operation", + )?; + validate_projection_text(node_key_field, "target-configuration.echo-operation")?; + validate_projection_text(replacement_field, "target-configuration.echo-operation")?; + if node_key_field == replacement_field || text_field(invocation, "nodeIdDerivation") != Some("sha256-utf8/v1") || text_field(invocation, "warpIdSource") != Some("action-lane/v1") { @@ -587,6 +623,8 @@ fn validate_configuration( steps: required_u64(budget, "steps", "target-configuration.echo-operation")?, read_bytes: required_u64(budget, "readBytes", "target-configuration.echo-operation")?, write_bytes: required_u64(budget, "writeBytes", "target-configuration.echo-operation")?, + node_key_field, + replacement_field, }; if configuration.max_replacement_bytes == 0 || configuration.steps < 3 @@ -600,12 +638,248 @@ fn validate_configuration( Ok(configuration) } +fn validate_result_projection( + value: &CanonicalValueV1, + input: &SemanticInput, + target_ir: &CanonicalValueV1, + intent: &ApplicationIntent<'_>, + configuration: ProgramConfiguration<'_>, +) -> Result { + if input.artifact.artifact.bytes.len() > MAX_RESULT_PROJECTION_ARTIFACT_BYTES { + return Err(invalid_artifact( + &input.role, + "result projection exceeds the canonical byte bound", + )); + } + require_exact_fields( + value, + &[ + "expression", + "maxOutputBytes", + "operationCoordinate", + "outputType", + "schema", + ], + &input.role, + )?; + if text_field(value, "schema") != Some(RESULT_PROJECTION_ABI) + || text_field(value, "operationCoordinate") != Some(intent.operation_coordinate.as_str()) + || input.artifact.reference.coordinate != intent.operation_coordinate + { + return Err(invalid_artifact( + &input.role, + "result projection is rebound from the application operation", + )); + } + validate_projection_text( + required_nonempty_text(value, "outputType", &input.role)?, + &input.role, + )?; + let max_output_bytes = required_u64(value, "maxOutputBytes", &input.role)?; + if max_output_bytes == 0 || max_output_bytes > MAX_APPLICATION_RESULT_BYTES { + return Err(invalid_artifact( + &input.role, + "result projection output bound is outside the Echo runtime ceiling", + )); + } + let target_intents = required_map(target_ir, "intents", &input.role)?; + let target_intent = required_map_field( + target_intents, + intent.name, + "result-projection.target-intent", + )?; + let [target_step] = required_array(target_intent, "steps", &input.role)?.as_slice() else { + return Err(super::unsupported_semantics( + "result-projection.target-steps", + )); + }; + let target_step_id = required_nonempty_text(target_step, "id", &input.role)?; + let mut nodes = 0; + let runtime_expression = lower_projection_expression( + required_map(value, "expression", &input.role)?, + target_step_id, + configuration.node_key_field, + &mut nodes, + &input.role, + )?; + Ok(ResultProjectionPlan { + runtime_expression, + node_key_path: vec![configuration.node_key_field.to_owned()], + replacement_path: vec![configuration.replacement_field.to_owned()], + }) +} + +fn lower_projection_expression( + value: &CanonicalValueV1, + target_step_id: &str, + node_key_field: &str, + nodes: &mut usize, + subject: &str, +) -> Result { + *nodes = nodes + .checked_add(1) + .ok_or_else(|| invalid_artifact(subject, "result projection node count overflowed"))?; + if *nodes > MAX_RESULT_PROJECTION_NODES { + return Err(invalid_artifact( + subject, + "result projection exceeds the expression-node bound", + )); + } + match required_text(value, "kind", subject)? { + "record" => { + require_exact_fields(value, &["fields", "kind"], subject)?; + let entries = as_map(required_map(value, "fields", subject)?) + .ok_or_else(|| invalid_artifact(subject, "projection fields must be a map"))?; + let mut lowered = Vec::with_capacity(entries.len()); + for (name, expression) in entries { + let Some(name) = as_text(name) else { + return Err(invalid_artifact( + subject, + "projection field names must be text", + )); + }; + validate_projection_text(name, subject)?; + lowered.push(( + name.to_owned(), + lower_projection_expression( + expression, + target_step_id, + node_key_field, + nodes, + subject, + )?, + )); + } + Ok(canonical_map([ + ("kind", canonical_text("record")), + ( + "fields", + CanonicalValueV1::Map( + lowered + .into_iter() + .map(|(name, value)| (canonical_text(&name), value)) + .collect(), + ), + ), + ])) + } + "source" => { + require_exact_fields(value, &["kind", "path", "source"], subject)?; + let source = required_map(value, "source", subject)?; + let source_kind = required_text(source, "kind", subject)?; + let path = required_array(value, "path", subject)?; + if path.len() > MAX_RESULT_PROJECTION_PATH_SEGMENTS { + return Err(invalid_artifact( + subject, + "result projection path exceeds the segment bound", + )); + } + let mut lowered_path = Vec::with_capacity(path.len()); + for segment in path { + let Some(segment) = as_text(segment) else { + return Err(invalid_artifact( + subject, + "result projection path segment must be text", + )); + }; + validate_projection_text(segment, subject)?; + lowered_path.push(segment.to_owned()); + } + match source_kind { + "applicationInput" => { + require_exact_fields(source, &["kind"], subject)?; + } + "capabilityResult" => { + require_exact_fields(source, &["kind", "stepId"], subject)?; + if required_text(source, "stepId", subject)? != target_step_id + || lowered_path != [node_key_field] + { + return Err(super::unsupported_semantics( + "result-projection.capability-result", + )); + } + lowered_path = vec![node_key_field.to_owned()]; + } + _ => { + return Err(invalid_artifact( + subject, + "result projection names an unsupported source kind", + )); + } + } + Ok(canonical_map([ + ("kind", canonical_text("source")), + ( + "path", + CanonicalValueV1::Array( + lowered_path + .into_iter() + .map(|segment| canonical_text(&segment)) + .collect(), + ), + ), + ( + "source", + canonical_map([("kind", canonical_text("applicationInput"))]), + ), + ])) + } + _ => Err(invalid_artifact( + subject, + "result projection names an unsupported expression kind", + )), + } +} + +fn require_exact_fields( + value: &CanonicalValueV1, + expected: &[&str], + subject: &str, +) -> Result<(), ProviderRefusalV1> { + let entries = as_map(value) + .ok_or_else(|| invalid_artifact(subject, "result projection node must be a map"))?; + let mut actual = BTreeSet::new(); + for (key, _) in entries { + let Some(key) = as_text(key) else { + return Err(invalid_artifact( + subject, + "result projection map key must be text", + )); + }; + if !actual.insert(key) { + return Err(invalid_artifact( + subject, + "result projection repeats a map field", + )); + } + } + let expected = expected.iter().copied().collect::>(); + if actual != expected { + return Err(invalid_artifact( + subject, + "result projection has an unexpected field set", + )); + } + Ok(()) +} + +fn validate_projection_text(value: &str, subject: &str) -> Result<(), ProviderRefusalV1> { + if value.is_empty() || value.len() > MAX_RESULT_PROJECTION_TEXT_BYTES { + return Err(invalid_artifact( + subject, + "result projection text is empty or exceeds its byte bound", + )); + } + Ok(()) +} + fn encode_expected_package( request: &VerificationRequestV1, closure: &ClosureInputs<'_>, intent: &ApplicationIntent<'_>, obstruction_coordinate: &str, configuration: ProgramConfiguration<'_>, + result_projection: &ResultProjectionPlan, ) -> Result, ProviderRefusalV1> { let program = canonical_map([ ( @@ -666,6 +940,45 @@ fn encode_expected_package( ), ]); let package = canonical_map([ + ( + "application_result_projection", + canonical_map([ + ( + "application_input_node_key_path", + CanonicalValueV1::Array( + result_projection + .node_key_path + .iter() + .map(|segment| canonical_text(segment)) + .collect(), + ), + ), + ( + "application_input_replacement_path", + CanonicalValueV1::Array( + result_projection + .replacement_path + .iter() + .map(|segment| canonical_text(segment)) + .collect(), + ), + ), + ( + "artifact_bytes", + CanonicalValueV1::Bytes( + closure.result_projection.artifact.artifact.bytes.clone(), + ), + ), + ( + "artifact_identity", + hash_value(hash_from_bound(&closure.result_projection.artifact)?), + ), + ( + "runtime_expression", + result_projection.runtime_expression.clone(), + ), + ]), + ), ( "application_basis_schema_identity", hash_value(profile_digest(APPLICATION_BASIS_SCHEMA)), @@ -750,11 +1063,21 @@ fn encode_expected_package( fn build_report( package: &super::ResourceRef, target_ir: &super::ResourceRef, + result_projection: &super::ResourceRef, outcome: &str, diagnostic_bytes: Vec, ) -> Result, ProviderRefusalV1> { let report = canonical_sorted_map([ ("apiVersion", canonical_text(REPORT_ABI)), + ( + "applicationResultProjection", + resource_ref_value(result_projection).map_err(|()| { + invalid_artifact( + REPORT_ROLE, + "result projection reference could not be encoded", + ) + })?, + ), ( "package", resource_ref_value(package).map_err(|()| { diff --git a/crates/echo-edict-provider-verifier/tests/executable_operation_package.rs b/crates/echo-edict-provider-verifier/tests/executable_operation_package.rs index f74fb156..9c27b5c3 100644 --- a/crates/echo-edict-provider-verifier/tests/executable_operation_package.rs +++ b/crates/echo-edict-provider-verifier/tests/executable_operation_package.rs @@ -13,6 +13,7 @@ use echo_edict_provider_verifier as verifier; const TARGET_PROFILE: &[u8] = include_bytes!("../resources/target-profile.echo-dpo.cbor"); const PACKAGE_ROLE: &str = "executable-operation-package.echo"; const PACKAGE_DOMAIN: &str = "echo.operation-package/v1"; +const RESULT_PROJECTION_DOMAIN: &str = "edict.result-projection.artifact/v1"; const REPORT_ROLE: &str = "verifier-report.echo-operation"; const REPORT_DOMAIN: &str = "echo.operation-package-verifier-report/v1"; const TARGET_INTRINSIC: &str = "echo.dpo@1.anchored-node-attachment-create-if-absent"; @@ -86,6 +87,7 @@ struct RawFixture { source: Vec, configuration: Vec, target_ir: Vec, + result_projection: Vec, } #[test] @@ -116,6 +118,12 @@ fn verifier_accepts_generic_lowerer_output_for_two_application_vocabularies() { let report = decode_canonical_cbor_v1(&report.artifact.bytes) .expect("the relation report is canonical"); assert_eq!(text_field(&report, "outcome"), Some("accepted")); + let projection = map_field(&report, "applicationResultProjection"); + let expected_projection_coordinate = format!("{}.{}", names.application, names.intent); + assert_eq!( + text_field(projection, "id"), + Some(expected_projection_coordinate.as_str()) + ); } } @@ -167,6 +175,123 @@ fn verifier_rejects_a_canonical_package_with_a_rebound_obstruction_coordinate() assert_eq!(text_field(&report, "outcome"), Some("rejected")); } +#[test] +fn verifier_rejects_a_package_with_substituted_projection_bytes() { + let names = FIXTURES[0]; + let fixture = raw_fixture(names); + let package = lower_package(names, &fixture); + let mut package_value = + decode_canonical_cbor_v1(&package).expect("the lowered package is canonical"); + let projection = map_field_mut(&mut package_value, "application_result_projection"); + *map_field_mut(projection, "artifact_bytes") = + CanonicalValueV1::Bytes(canonical_bytes(&result_projection_with_fields(names, 2))); + let package = encode_canonical_cbor_v1(&package_value).expect("the mutation remains canonical"); + + let verified = verifier::verify(verification_request(names, &fixture, package)) + .expect("semantic mismatch is a completed verification"); + + assert_eq!(verified.diagnostics.len(), 1); + assert_eq!( + verified.diagnostics[0].code, + "echo.verifier.executable-operation-package-mismatch" + ); +} + +#[test] +fn verifier_requires_the_compiler_projection_input() { + let names = FIXTURES[0]; + let fixture = raw_fixture(names); + let package = lower_package(names, &fixture); + let mut request = verification_request(names, &fixture, package); + request.semantic_inputs.retain(|input| { + input.kind != verifier::SemanticInputKind::Auxiliary("result-projection".to_owned()) + }); + + let refusal = verifier::verify(request).expect_err("a projection-free closure must refuse"); + + assert_eq!( + refusal.kind, + verifier::ProviderRefusalKind::UnsupportedSemantics + ); +} + +#[test] +fn verifier_refuses_a_projection_above_the_echo_runtime_output_ceiling() { + let names = FIXTURES[0]; + let package_fixture = raw_fixture(names); + let package = lower_package(names, &package_fixture); + let fixture = raw_fixture_with_values( + names, + configuration(names), + result_projection_with_max_output(names, 65_537), + ); + + let refusal = verifier::verify(verification_request(names, &fixture, package)) + .expect_err("an impossible Echo output ceiling must be an invalid semantic artifact"); + + assert_eq!( + refusal.kind, + verifier::ProviderRefusalKind::InvalidSemanticArtifact + ); +} + +#[test] +fn verifier_refuses_equal_invocation_binding_fields() { + let names = FIXTURES[0]; + let package_fixture = raw_fixture(names); + let package = lower_package(names, &package_fixture); + let fixture = raw_fixture_with_values( + names, + configuration_with_fields(names, "key", "key"), + result_projection(names), + ); + + let refusal = verifier::verify(verification_request(names, &fixture, package)) + .expect_err("one input field cannot bind two distinct runtime values"); + + assert_eq!( + refusal.kind, + verifier::ProviderRefusalKind::UnsupportedSemantics + ); +} + +#[test] +fn verifier_bounds_invocation_binding_field_lengths() { + let names = FIXTURES[0]; + let boundary = "x".repeat(1_024); + for (node_key_field, replacement_field) in + [(boundary.as_str(), "value"), ("key", boundary.as_str())] + { + let fixture = raw_fixture_with_values( + names, + configuration_with_fields(names, node_key_field, replacement_field), + result_projection_with_node_key(names, node_key_field), + ); + let package = lower_package(names, &fixture); + verifier::verify(verification_request(names, &fixture, package)) + .expect("the exact invocation-binding field boundary is accepted"); + } + + let package_fixture = raw_fixture(names); + let package = lower_package(names, &package_fixture); + let over_limit = "x".repeat(1_025); + for (node_key_field, replacement_field) in + [(over_limit.as_str(), "value"), ("key", over_limit.as_str())] + { + let fixture = raw_fixture_with_values( + names, + configuration_with_fields(names, node_key_field, replacement_field), + result_projection(names), + ); + let refusal = verifier::verify(verification_request(names, &fixture, package.clone())) + .expect_err("an oversized invocation-binding field must fail closed"); + assert_eq!( + refusal.kind, + verifier::ProviderRefusalKind::InvalidSemanticArtifact + ); + } +} + fn lower_package(names: FixtureNames<'_>, fixture: &RawFixture) -> Vec { let success = lowerer::lower(lowering_request(names, fixture)).expect("the generic lowerer completes"); @@ -222,6 +347,14 @@ fn lowering_request(names: FixtureNames<'_>, fixture: &RawFixture) -> lowerer::L &fixture.target_ir, ), ), + lowerer_input( + lowerer::SemanticInputKind::Auxiliary("result-projection".to_owned()), + lowerer_bound( + &format!("{}.{}", names.application, names.intent), + RESULT_PROJECTION_DOMAIN, + &fixture.result_projection, + ), + ), ], requested_outputs: vec![lowerer::LoweringOutputRequest { role: PACKAGE_ROLE.to_owned(), @@ -287,6 +420,14 @@ fn verification_request( &fixture.configuration, ), ), + verifier_input( + verifier::SemanticInputKind::Auxiliary("result-projection".to_owned()), + verifier_bound( + &format!("{}.{}", names.application, names.intent), + RESULT_PROJECTION_DOMAIN, + &fixture.result_projection, + ), + ), ], requested_outputs: vec![verifier::VerificationOutputRequest { role: REPORT_ROLE.to_owned(), @@ -302,11 +443,19 @@ fn verification_request( } fn raw_fixture(names: FixtureNames<'_>) -> RawFixture { + raw_fixture_with_values(names, configuration(names), result_projection(names)) +} + +fn raw_fixture_with_values( + names: FixtureNames<'_>, + configuration_value: CanonicalValueV1, + result_projection_value: CanonicalValueV1, +) -> RawFixture { let target_profile = TARGET_PROFILE.to_vec(); let target_profile_ref = raw_ref("echo.dpo@1", "edict.target-profile/v1", &target_profile); let exports = canonical_bytes(&exports(names)); let exports_ref = raw_ref(names.exports, "edict.lawpack-exports/v1", &exports); - let configuration = canonical_bytes(&configuration(names)); + let configuration = canonical_bytes(&configuration_value); let configuration_ref = raw_ref( names.configuration, "echo.operation-lowering-configuration/v1", @@ -342,6 +491,7 @@ fn raw_fixture(names: FixtureNames<'_>) -> RawFixture { &lawpack_ref, &target_profile_ref, )); + let result_projection = canonical_bytes(&result_projection_value); RawFixture { core, target_profile, @@ -351,6 +501,7 @@ fn raw_fixture(names: FixtureNames<'_>) -> RawFixture { source, configuration, target_ir, + result_projection, } } @@ -450,6 +601,14 @@ fn exports(names: FixtureNames<'_>) -> CanonicalValueV1 { } fn configuration(names: FixtureNames<'_>) -> CanonicalValueV1 { + configuration_with_fields(names, "key", "value") +} + +fn configuration_with_fields( + names: FixtureNames<'_>, + node_key_field: &str, + replacement_field: &str, +) -> CanonicalValueV1 { map([ ( "apiVersion", @@ -474,8 +633,8 @@ fn configuration(names: FixtureNames<'_>) -> CanonicalValueV1 { ( "invocationBinding", map([ - ("nodeKeyField", text("key")), - ("replacementField", text("value")), + ("nodeKeyField", text(node_key_field)), + ("replacementField", text(replacement_field)), ("nodeIdDerivation", text("sha256-utf8/v1")), ("warpIdSource", text("action-lane/v1")), ]), @@ -574,6 +733,7 @@ fn target_ir( ( "steps", CanonicalValueV1::Array(vec![map([ + ("id", text("step.0")), ("targetIntrinsic", text(TARGET_INTRINSIC)), ( "obstructionFailures", @@ -587,6 +747,93 @@ fn target_ir( ]) } +fn result_projection(names: FixtureNames<'_>) -> CanonicalValueV1 { + result_projection_with_max_output(names, 512) +} + +fn result_projection_with_max_output( + names: FixtureNames<'_>, + max_output_bytes: u64, +) -> CanonicalValueV1 { + result_projection_with_fields_and_max_output(names, 1, max_output_bytes) +} + +fn result_projection_with_fields(names: FixtureNames<'_>, field_count: usize) -> CanonicalValueV1 { + result_projection_with_fields_and_max_output(names, field_count, 512) +} + +fn result_projection_with_fields_and_max_output( + names: FixtureNames<'_>, + field_count: usize, + max_output_bytes: u64, +) -> CanonicalValueV1 { + result_projection_with_fields_max_output_and_node_key( + names, + field_count, + max_output_bytes, + "key", + ) +} + +fn result_projection_with_node_key( + names: FixtureNames<'_>, + node_key_field: &str, +) -> CanonicalValueV1 { + result_projection_with_fields_max_output_and_node_key(names, 1, 512, node_key_field) +} + +fn result_projection_with_fields_max_output_and_node_key( + names: FixtureNames<'_>, + field_count: usize, + max_output_bytes: u64, + node_key_field: &str, +) -> CanonicalValueV1 { + let fields = (0..field_count) + .map(|index| { + let source = if index == 0 { + map([ + ("kind", text("capabilityResult")), + ("stepId", text("step.0")), + ]) + } else { + map([("kind", text("applicationInput"))]) + }; + let path = if index == 0 { node_key_field } else { "value" }; + ( + format!("field-{index}"), + map([ + ("kind", text("source")), + ("source", source), + ("path", CanonicalValueV1::Array(vec![text(path)])), + ]), + ) + }) + .collect::>(); + map([ + ("schema", text("edict.result-projection/v1")), + ( + "operationCoordinate", + text(format!("{}.{}", names.application, names.intent)), + ), + ("outputType", text(format!("{}.Output", names.application))), + ("maxOutputBytes", integer(max_output_bytes)), + ( + "expression", + map([ + ("kind", text("record")), + ( + "fields", + dynamic_map( + fields + .iter() + .map(|(name, value)| (name.as_str(), value.clone())), + ), + ), + ]), + ), + ]) +} + fn lowerer_input( kind: lowerer::SemanticInputKind, artifact: lowerer::BoundArtifact, @@ -693,6 +940,16 @@ fn map_field_mut<'a>(value: &'a mut CanonicalValueV1, field: &str) -> &'a mut Ca .unwrap_or_else(|| panic!("missing field {field}")) } +fn map_field<'a>(value: &'a CanonicalValueV1, field: &str) -> &'a CanonicalValueV1 { + let CanonicalValueV1::Map(entries) = value else { + panic!("expected map"); + }; + entries + .iter() + .find_map(|(key, value)| (key == &text(field)).then_some(value)) + .unwrap_or_else(|| panic!("missing field {field}")) +} + fn text_field<'a>(value: &'a CanonicalValueV1, field: &str) -> Option<&'a str> { let CanonicalValueV1::Map(entries) = value else { return None; diff --git a/crates/echo-wesley-gen/README.md b/crates/echo-wesley-gen/README.md index ed4017fb..7e7b6476 100644 --- a/crates/echo-wesley-gen/README.md +++ b/crates/echo-wesley-gen/README.md @@ -41,7 +41,8 @@ Apache-2.0 contract pack checked under [`schemas/edict-provider/contracts/v1/`](../../schemas/edict-provider/contracts/v1/README.md) is admitted through `provider_contract_pack::admit_provider_contract_pack_v1(...)`. Admission -requires the pinned Edict PR #162 CDDL and manifest publication, verifies every +requires the pinned Edict contract-pack publication from PR #162 as extended +with the result-projection contract in PR #174, verifies every embedded contract resource and provenance record, and performs no discovery or mutable coordinate resolution. This authenticates the schema publication; it does not by itself claim that a generated artifact is a valid schema instance. @@ -117,8 +118,8 @@ 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, 30 schema bindings (nine compatibility invocation domains, the -generated artifact profile, 14 generated-resource domains, and six generic +routes, 31 schema bindings (nine compatibility invocation domains, the +generated artifact profile, 14 generated-resource domains, and seven generic executable-operation closure domains), and raw SHA-256 of every non-manifest member. Canonical-CBOR artifact routes retain their Edict domain-framed identities; 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 index c3b2b5ad..5df2ec6a 100644 --- 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 @@ -583,7 +583,7 @@ lawpack-adapter-budget = { } lawpack-adapter-write-class = "none" / "read" / "create" / "ensure" / - "append" / "modify" / "delete" + "append" / "replace" / "delete" / "custom" ; failure-ident is defined in edict-common.cddl. @@ -789,6 +789,45 @@ authority-budget-fact = { authority-write-class = "none" / "read" / "create" / "ensure" / "append" / "replace" / "delete" / "custom" +; --- edict-result-projection.cddl --- +; SPDX-License-Identifier: Apache-2.0 +; edict-result-projection.cddl +; Canonical schema for compiler-owned application-result projections. +; Authoritative byte encoding: edict.canonical-cbor/v1. + +result-projection = { + schema: "edict.result-projection/v1", + operationCoordinate: bounded-projection-text, + outputType: bounded-projection-text, + maxOutputBytes: uint .gt 0, + expression: result-projection-expr, +} + +result-projection-expr = result-projection-record / result-projection-source + +result-projection-record = { + kind: "record", + ; The root record counts as one of the Rust decoder's 256 expression nodes. + ; Nested aggregate node count remains an authoritative decoder check. + fields: { 0*255 bounded-projection-text => result-projection-expr }, +} + +result-projection-source = { + kind: "source", + source: result-projection-source-kind, + ; Matches MAX_RESULT_PROJECTION_PATH_SEGMENTS in edict-syntax. + path: [0*32 bounded-projection-text], +} + +result-projection-source-kind = + { kind: "applicationInput" } / + { + kind: "capabilityResult", + stepId: bounded-projection-text, + } + +bounded-projection-text = tstr .size (1..1024) + ; --- edict-target-ir.cddl --- ; SPDX-License-Identifier: Apache-2.0 ; edict-target-ir.cddl 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 index f1cf149a..0106222a 100644 --- 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 @@ -3,8 +3,8 @@ "coordinate": "edict.provider-contract-pack.cddl@1", "license": "Apache-2.0", "schema": { - "bytesHex": "3b20535044582d4c6963656e73652d4964656e7469666965723a204170616368652d322e300a3b2065646963742d70726f76696465722d636f6e7472616374732e6364646c0a3b2047656e6572617465642066726f6d2045646963742d6f776e65642041424920667261676d656e74732e20444f204e4f5420454449542e0a0a3b202d2d2d2065646963742d636f6d6d6f6e2e6364646c202d2d2d0a3b2065646963742d636f6d6d6f6e2e6364646c0a3b20536861726564204344444c20747970657320666f722074686520456469637420414249732c20646566696e6564204f4e4345206865726520736f20746865792063616e6e6f742064726966740a3b202845444943542d4142492d4e4f4455502d303031292e2054776f2067726f7570733a0a3b2020202d207265736f757263652d7265662c207368613235362d6469676573742c206566666563742d6661696c7572652d626f64792c206566666563742d6b696e642c20617574686f726974792d636c6173732c0a3b2020202020636f72652d747970652d7265663a20617373656d626c656420776974682065646963742d7461726765742d70726f66696c652e6364646c20616e640a3b202020202065646963742d6c61777061636b2e6364646c20627920746865206275696c643b2074686f736520736368656d617320646f206e6f74207265646566696e65207468656d2e0a3b2020202d206f7065726174696f6e2d70726f66696c652c206f707469632d74656d706c6174652c2061706572747572652d726571756972656d656e7420616e6420746865697220726566733a0a3b2020202020636f6e73756d65642062792074686520436f72652f6f70746963206c61796572202865646963742d636f72652e6364646c2920616e64207265666572656e636564206279207468650a3b20202020206c616e67756167652f7461726765742d70726f66696c652073706563732e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a0a3b2041206e6f726d617469766520737562636f6d706f6e656e74207265666572656e636564206279206964656e7469747920706c7573206469676573742e204d616e696665737473206e657665720a3b20656d626564207468656972206f776e2073656c662d64696765737420696e20746865697220707265696d616765202845444943542d434f52452d53454c46484153482d303031292e0a7265736f757263652d726566203d207b2069643a20747374722c206469676573743a207368613235362d646967657374207d0a0a3b20446967657374732061726520617574686f726974617469766520617320747970656420627974652076616c7565732c206e657665722068657820737472696e67732e20526576696577204a534f4e0a3b2072656e64657273207468697320617320227368613235363a3c3634206c6f77657263617365206865783e22202845444943542d4449474553542d574952452d303031292e0a7368613235362d646967657374203d205b20616c676f726974686d3a2022736861323536222c2062797465733a2062737472202e73697a65203332205d0a0a3b2041206e616d6564206c6f772d6c6576656c206661696c75726520616e206566666563742063616e2072616973652e2054686520736f75726365206f62737472756374696f6e206d61700a3b2062696e64732069742028627920636f6f7264696e6174652920616e6420636f6e73747275637473206120747970656420646f6d61696e206f62737472756374696f6e2066726f6d206974730a3b207061796c6f6164202845444943542d4142492d4641494c5552452d4e414d45442d303031292e0a3b20416e20656666656374277320606566666563744661696c7572657360206c697374204d555354206861766520756e697175652060636f6f7264696e61746560733a2073696e6365207468650a3b206f62737472756374696f6e206d6170206973206b6579656420627920636f6f7264696e6174652c2074776f206661696c757265732073686172696e67206120636f6f7264696e61746520286576656e0a3b207769746820646966666572656e7420617574686f72697479436c6173732f7061796c6f61645479706529206d616b652065786861757374697665206d617070696e6720616e642062696e6465720a3b20747970696e6720616d626967756f757320616e64206172652072656a6563746564202845444943542d4142492d4641494c5552452d554e495155452d303031292e0a3b0a3b2045666665637473206361727279207468656972206661696c757265732061732061206d617020607b206661696c7572652d6964656e74203d3e206566666563742d6661696c7572652d626f6479207d600a3b202873656520746865207461726765742f6c61777061636b2065666665637420736368656d6173292e20546865206661696c75726520636f6f7264696e61746520697320746865206d61700a3b204b45592c20736f206974206973206e6f7420726570656174656420696e2074686520626f647920616e642063616e6e6f74206469736167726565207769746820746865206b65792e0a6566666563742d6661696c7572652d626f6479203d207b0a2020617574686f72697479436c6173733a20617574686f726974792d636c6173732c0a20207061796c6f6164547970653a20636f72652d747970652d7265662c202020202020202020202020203b2074797065642c20626f756e64656420286d617920626520656d707479207265636f7264290a7d0a0a3b2041206661696c75726520636f6f7264696e617465206d7573742062652061206261726520456469637420606964656e746020286c65747465722f756e64657273636f7265207468656e0a3b206c6574746572732f6469676974732f756e64657273636f7265732920414e44206d757374206e6f742062652061207265736572766564206b6579776f72642028652e672e2060656c7365602c0a3b20606261736973602c20607768657265602c206072657175697265602c2060666f72602c2060696660292e2054686520736f75726365206f62737472756374696f6e2d6d6170204c4853206f6e6c790a3b20616363657074732061206e6f6e2d6b6579776f726420606964656e74602c20736f20612068797068656e2f646f742f6b6579776f726420636f6f7264696e61746520776f756c642062650a3b204142492d76616c69642079657420696d706f737369626c6520746f206d617020657868617573746976656c7920696e20736f757263652e20546865207265676578206361707475726573207468650a3b206c65786963616c2073686170653b206b6579776f7264206578636c7573696f6e20697320616e206164646974696f6e616c2076616c69646174696f6e2072756c650a3b202845444943542d4142492d4641494c5552452d4944454e542d303031292e0a6661696c7572652d6964656e74203d2074737472202e72656765787020225b412d5a612d7a5f5d5b412d5a612d7a302d395f5d2a220a0a6566666563742d6b696e64203d20227265616422202f202263726561746522202f2022656e7375726522202f20227265706c61636522202f202264656c65746522202f0a202020202020202020202020202022617070656e6422202f202272656475636522202f202273656d616e7469632e656d697422202f2022637573746f6d220a0a617574686f726974792d636c617373203d2022646f6d61696e4d61707061626c6522202f20227061727469636970616e744f776e656422202f2022696e746567726974794661756c7422202f0a202020202020202020202020202020202020227265736f757263654661756c7422202f2022696e7465726e616c4661756c74220a0a636f72652d747970652d726566203d20747374722020203b2063616e6f6e6963616c20436f7265207479706520636f6f7264696e6174650a0a3b20416e206f7065726174696f6e2070726f66696c6520737570706c69657320746865206f707469632074656d706c617465206120436f726520696e74656e74207265736f6c766573206974730a3b206f707469634b696e642f626f756e646172794b696e642f737570706f7274506f6c6963792f6c6f7373446973706f736974696f6e2066726f6d2e205461726765742070726f66696c657320616e640a3b206c61777061636b73207075626c6973682074686573652061732061206d617020607b20636f6f7264696e617465203d3e206f7065726174696f6e2d70726f66696c65207d602c20736f207468650a3b20636f6f7264696e61746520697320746865204b45592c206e6f7420612076616c7565206669656c64202845444943542d4f505449432d54454d504c4154452d4f574e45522d3030312c0a3b2045444943542d4142492d4f5050524f46494c452d554e495155452d303031292e0a6f7065726174696f6e2d70726f66696c65203d207b0a20206f7074696354656d706c6174653a206f707469632d74656d706c6174652c0a20206566666563745072656469636174653a20747374722c20202020202020202020203b20636f6f7264696e617465206f6620746865206f7065726174696f6e2d6d6f6465207072656469636174650a7d0a0a6f707469632d74656d706c617465203d207b0a20206f707469634b696e643a2022726576656c6174696f6e22202f20226166666563745265696e746567726174696f6e222c0a2020626f756e646172794b696e643a202270726f6a656374696f6e22202f2022616666656374222c0a2020737570706f7274506f6c6963793a20747374722c202020202020202020202020203b2063616e6f6e6963616c20737570706f72742d706f6c69637920636f6f7264696e6174650a20206c6f7373446973706f736974696f6e3a20747374722c20202020202020202020203b2063616e6f6e6963616c206c6f73732d646973706f736974696f6e20636f6f7264696e6174650a20203f20626173697354656d706c6174653a20747374722c20202020202020202020203b206f7074696f6e616c206469676573742d6c6f636b65642062617369732074656d706c61746520636f6f72640a20203b2074686520617065727475726520726571756972656d656e7420746869732074656d706c61746520737570706c6965732e205265717569726564207768656e207468652074656d706c6174650a20203b2069732074686520736f75726365206f66206120436f7265206f707469632773206170657274757265526571756972656d656e742028692e652e2074686520696e74656e7420686173206e6f0a20203b20736f757263652060666f6f747072696e74203c3d202e2e2e60292c2073696e6365206170657274757265526571756972656d656e74206973206d616e6461746f727920696e20436f72650a20203b202845444943542d4f505449432d41504552545552452d5245462d303031292e0a20203f206170657274757265526571756972656d656e743a2061706572747572652d726571756972656d656e742c0a7d0a0a3b206170657274757265526571756972656d656e742069732061207479706564207265666572656e63652c206e65766572206120667265652d666f726d20737472696e672e2041207265766965770a3b2072656e646572696e67206d61792073686f772069747320636f6f7264696e617465202845444943542d4f505449432d41504552545552452d5245462d303031292e0a61706572747572652d726571756972656d656e74203d20666f6f747072696e742d6365696c696e672d726566202f2061627374726163742d666f6f747072696e742d6f626c69676174696f6e2d7265660a666f6f747072696e742d6365696c696e672d726566203d207b206b696e643a2022666f6f747072696e744365696c696e67222c207265663a2074737472207d0a61627374726163742d666f6f747072696e742d6f626c69676174696f6e2d726566203d207b206b696e643a20226162737472616374466f6f747072696e744f626c69676174696f6e222c207265663a2074737472207d0a0a3b202d2d2d2065646963742d636f72652e6364646c202d2d2d0a3b2065646963742d636f72652e6364646c0a3b204e6f726d617469766520736368656d6120666f722074686520456469637420436f72652076312073656d616e746963206d6f64656c2e0a3b0a3b2053636f706520626f756e646172793a20746869732066696c6520646566696e657320436f7265206d65616e696e6720616e6420736368656d61207368617065206f6e6c792e20497420646f65730a3b206e6f7420646566696e6520612063616e6f6e6963616c20656e636f6465722c20436f7265206d6f64756c652068617368206669656c64732c20686173682066697874757265732c207461726765740a3b206c6f776572696e672c2061646d697373696f6e2062756e646c65732c206f72207461726765742d6f776e65642049522e0a0a636f72652d6d6f64756c65203d207b0a202061706956657273696f6e3a202265646963742e636f72652f7631222c0a2020636f6f7264696e6174653a20747374722c0a2020696d706f7274733a205b2a20636f72652d696d706f72745d2c0a202074797065733a207b202a2074737472203d3e20636f72652d74797065207d2c0a2020696e74656e74733a207b202b2074737472203d3e20636f72652d696e74656e74207d2c0a20207265717569726564436f72654361706162696c69746965733a205b2a20747374725d2c0a7d0a0a636f72652d696d706f7274203d207b0a20206b696e643a20226c61777061636b22202f202274617267657422202f2022636f7265222c0a20207265663a207265736f757263652d7265662c0a20203f20616c6961733a20747374722c0a7d0a0a3b202d2d2d207479706573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a636f72652d74797065203d20636f72652d7363616c61722d74797065202f20636f72652d7265636f72642d74797065202f20636f72652d76617269616e742d74797065202f0a202020202020202020202020636f72652d6f7074696f6e2d74797065202f20636f72652d6c6973742d74797065202f20636f72652d6d61702d74797065202f0a202020202020202020202020636f72652d6361706162696c6974792d7265662d747970650a0a636f72652d7363616c61722d74797065203d20636f72652d626f6f6c2d74797065202f20636f72652d696e742d74797065202f20636f72652d737472696e672d74797065202f0a20202020202020202020202020202020202020636f72652d62797465732d74797065202f20636f72652d756e69742d747970650a0a636f72652d626f6f6c2d74797065203d207b206b696e643a2022426f6f6c22207d0a636f72652d756e69742d74797065203d207b206b696e643a2022556e697422207d0a636f72652d696e742d74797065203d207b0a20206b696e643a202249363422202f202255363422202f202249333222202f202255333222202f202249313622202f202255313622202f2022493822202f20225538222c0a7d0a636f72652d737472696e672d74797065203d207b0a20206b696e643a2022537472696e67222c0a20206d61783a2075696e742c0a202063616e6f6e6963616c3a2022756e69636f64652d7363616c61722d6e666322202f20227261772d75746638222c0a7d0a636f72652d62797465732d74797065203d207b0a20206b696e643a20224279746573222c0a20206d61783a2075696e742c0a7d0a636f72652d7265636f72642d74797065203d207b0a20206b696e643a20225265636f7264222c0a20206669656c64733a207b202a2074737472203d3e20636f72652d747970652d726566207d2c0a7d0a636f72652d76617269616e742d74797065203d207b0a20206b696e643a202256617269616e74222c0a202063617365733a207b202b2074737472203d3e2076617269616e742d636173652d626f6479207d2c0a7d0a76617269616e742d636173652d626f6479203d207b0a20203f207061796c6f61643a20636f72652d747970652d7265662c0a7d0a636f72652d6f7074696f6e2d74797065203d207b0a20206b696e643a20224f7074696f6e222c0a20206974656d3a20636f72652d747970652d7265662c0a7d0a636f72652d6c6973742d74797065203d207b0a20206b696e643a20224c697374222c0a20206974656d3a20636f72652d747970652d7265662c0a20206d61783a2075696e742c0a7d0a636f72652d6d61702d74797065203d207b0a20206b696e643a20224d6170222c0a20206b65793a20636f72652d747970652d7265662c0a202076616c75653a20636f72652d747970652d7265662c0a20206d61783a2075696e742c0a7d0a636f72652d6361706162696c6974792d7265662d74797065203d207b0a20206b696e643a20224361706162696c697479526566222c0a20206974656d3a20636f72652d747970652d7265662c0a7d0a0a3b20636f72652d747970652d72656620697320646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d612e0a0a3b202d2d2d207265666572656e63657320616e642076616c756573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a3b204c6f63616c206964656e7469747920697320616c7068612d737461626c652e20606964602069732074686520636f6d70696c65722d6f776e6564206c6f63616c20636f6f7264696e6174653b0a3b2060616c7068614e616d656020697320746865206e6f726d616c697a65642068756d616e2f6465627567206e616d652e20536f757263652062696e646572207370656c6c696e67206973206e6f740a3b206964656e746974792e0a6c6f63616c2d726566203d207b0a202069643a20747374722c0a2020616c7068614e616d653a20747374722c0a2020747970653a20636f72652d747970652d7265662c0a7d0a0a636f72652d76616c7565203d20636f72652d6e756c6c2d76616c7565202f20636f72652d626f6f6c2d76616c7565202f20636f72652d696e742d76616c7565202f0a20202020202020202020202020636f72652d737472696e672d76616c7565202f20636f72652d62797465732d76616c7565202f20636f72652d7265636f72642d76616c7565202f0a20202020202020202020202020636f72652d76617269616e742d76616c7565202f20636f72652d6c6973742d76616c7565202f20636f72652d6d61702d76616c7565202f0a20202020202020202020202020636f72652d6361706162696c6974792d76616c75650a0a636f72652d6e756c6c2d76616c7565203d207b206b696e643a20226e756c6c22207d0a636f72652d626f6f6c2d76616c7565203d207b206b696e643a2022626f6f6c222c2076616c75653a20626f6f6c207d0a636f72652d696e742d76616c7565203d207b206b696e643a2022696e74222c2077696474683a20747374722c2076616c75653a20696e74207d0a636f72652d737472696e672d76616c7565203d207b206b696e643a2022737472696e67222c2076616c75653a2074737472207d0a636f72652d62797465732d76616c7565203d207b206b696e643a20226279746573222c2076616c75653a2062737472207d0a636f72652d7265636f72642d76616c7565203d207b206b696e643a20227265636f7264222c206669656c64733a207b202a2074737472203d3e20636f72652d76616c7565207d207d0a636f72652d76617269616e742d76616c7565203d207b0a20206b696e643a202276617269616e74222c0a2020747970653a20636f72652d747970652d7265662c0a2020636173653a20747374722c0a20203f207061796c6f61643a20636f72652d76616c75652c0a7d0a636f72652d6c6973742d76616c7565203d207b206b696e643a20226c697374222c2076616c7565733a205b2a20636f72652d76616c75655d207d0a636f72652d6d61702d76616c7565203d207b206b696e643a20226d6170222c20656e74726965733a205b2a205b6b65793a20636f72652d76616c75652c2076616c75653a20636f72652d76616c75655d5d207d0a636f72652d6361706162696c6974792d76616c7565203d207b0a20206b696e643a20226361706162696c697479222c0a2020726563656970743a207368613235362d6469676573742c0a7d0a0a3b2045646963742d617574686f72656420707572652068656c70657273207573652061207075726520436f72652066756e6374696f6e20626f64792e2054686520626f64792063616e2062696e640a3b20707572652065787072657373696f6e7320616e642072657475726e20616e2065787072657373696f6e2c206275742069742063616e6e6f7420636f6e7461696e20436f7265206566666563742c0a3b2067756172642c206272616e63682c206c6f6f702c206d617463682d6e6f64652c206f722070726f6f662d6f626c69676174696f6e206e6f6465732e0a636f72652d666e2d626f6479203d207b0a2020706172616d733a205b2a206c6f63616c2d7265665d2c0a2020626f64793a20636f72652d707572652d626c6f636b2c0a7d0a0a636f72652d707572652d626c6f636b203d207b0a20206c6f63616c733a205b2a206c6f63616c2d7265665d2c0a202062696e64696e67733a205b2a20707572652d6c65742d6e6f64655d2c0a2020726573756c743a20636f72652d657870722c0a7d0a0a707572652d6c65742d6e6f6465203d207b0a20206b696e643a20226c6574222c0a202062696e64696e673a206c6f63616c2d7265662c0a202076616c75653a20636f72652d657870722c0a7d0a0a3b202d2d2d2065787072657373696f6e7320616e642070726564696361746573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a636f72652d65787072203d206c6f63616c2d65787072202f20636f6e73742d65787072202f207265636f72642d65787072202f206669656c642d65787072202f0a20202020202020202020202076617269616e742d65787072202f206d617463682d65787072202f2063616c6c2d65787072202f206c6973742d65787072202f206d61702d65787072202f0a20202020202020202020202069662d657870720a0a6c6f63616c2d65787072203d207b206b696e643a20226c6f63616c222c207265663a206c6f63616c2d726566207d0a636f6e73742d65787072203d207b206b696e643a2022636f6e7374222c2076616c75653a20636f72652d76616c7565207d0a7265636f72642d65787072203d207b206b696e643a20227265636f7264222c206669656c64733a207b202a2074737472203d3e20636f72652d65787072207d207d0a6669656c642d65787072203d207b206b696e643a20226669656c64222c20626173653a20636f72652d657870722c206669656c643a2074737472207d0a76617269616e742d65787072203d207b0a20206b696e643a202276617269616e74222c0a2020747970653a20636f72652d747970652d7265662c0a2020636173653a20747374722c0a20203f207061796c6f61643a20636f72652d657870722c0a7d0a6d617463682d65787072203d207b0a20206b696e643a20226d61746368222c0a20207363727574696e65653a20636f72652d657870722c0a202061726d733a205b2b206d617463682d61726d5d2c0a7d0a6d617463682d61726d203d207b0a2020636173653a20747374722c0a20203f2062696e6465723a206c6f63616c2d7265662c0a2020626f64793a20636f72652d657870722c0a7d0a63616c6c2d65787072203d207b0a20206b696e643a202263616c6c222c0a202063616c6c65653a20747374722c0a202074797065417267733a205b2a20636f72652d747970652d7265665d2c0a2020617267733a205b2a20636f72652d657870725d2c0a7d0a6c6973742d65787072203d207b206b696e643a20226c697374222c2076616c7565733a205b2a20636f72652d657870725d207d0a6d61702d65787072203d207b206b696e643a20226d6170222c20656e74726965733a205b2a205b6b65793a20636f72652d657870722c2076616c75653a20636f72652d657870725d5d207d0a69662d65787072203d207b0a20206b696e643a20226966222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20207468656e3a20636f72652d657870722c0a2020656c73653a20636f72652d657870722c0a7d0a0a636f72652d707265646963617465203d20747275652d707265646963617465202f2066616c73652d707265646963617465202f206e6f742d707265646963617465202f0a2020202020202020202020202020202020616c6c2d707265646963617465202f20616e792d707265646963617465202f20636f6d706172652d707265646963617465202f0a202020202020202020202020202020202063616c6c2d707265646963617465202f206f62737472756374696f6e2d7072656469636174650a0a747275652d707265646963617465203d207b206b696e643a20227472756522207d0a66616c73652d707265646963617465203d207b206b696e643a202266616c736522207d0a6e6f742d707265646963617465203d207b206b696e643a20226e6f74222c2076616c75653a20636f72652d707265646963617465207d0a616c6c2d707265646963617465203d207b206b696e643a2022616c6c222c2076616c7565733a205b2b20636f72652d7072656469636174655d207d0a616e792d707265646963617465203d207b206b696e643a2022616e79222c2076616c7565733a205b2b20636f72652d7072656469636174655d207d0a636f6d706172652d707265646963617465203d207b0a20206b696e643a2022636f6d70617265222c0a20206f703a20223d3d22202f2022213d22202f20223c22202f20223c3d22202f20223e22202f20223e3d222c0a20206c6566743a20636f72652d657870722c0a202072696768743a20636f72652d657870722c0a7d0a63616c6c2d707265646963617465203d207b0a20206b696e643a202263616c6c222c0a20207072656469636174653a20747374722c0a2020617267733a205b2a20636f72652d657870725d2c0a7d0a6f62737472756374696f6e2d707265646963617465203d207b0a20206b696e643a20226f62737472756374696f6e222c0a2020636f6f7264696e6174653a206661696c7572652d6964656e742c0a20207061796c6f61643a20636f72652d657870722c0a7d0a0a696e7075742d636f6e73747261696e74203d207b0a2020636f6f7264696e6174653a20747374722c0a2020736f757263653a2022776865726522202f2022636f6d70696c6572222c0a20207072656469636174653a20636f72652d7072656469636174652c0a7d0a0a3b202d2d2d20696e74656e74732c20626c6f636b732c20616e64206e6f646573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a636f72652d696e74656e74203d207b0a2020696e7075743a20636f72652d747970652d7265662c0a20206f75747075743a20636f72652d747970652d7265662c0a202072657175697265644f7065726174696f6e50726f66696c653a20747374722c0a20203f2062617369733a20636f72652d657870722c0a2020696e707574436f6e73747261696e74733a205b2a20696e7075742d636f6e73747261696e745d2c0a2020636f72654576616c756174696f6e4275646765743a20636f72652d6275646765742c0a2020626f64793a20636f72652d626c6f636b2c0a20203f206f707469633a20636f72652d6f707469632c0a7d0a0a636f72652d627564676574203d207b0a20206d617853746570733a2075696e742c0a20206d6178416c6c6f636174656442797465733a2075696e742c0a20206d61784f757470757442797465733a2075696e742c0a7d0a0a636f72652d6f70746963203d207b0a20206f707469634b696e643a2022726576656c6174696f6e22202f20226166666563745265696e746567726174696f6e222c0a2020626f756e646172794b696e643a202270726f6a656374696f6e22202f2022616666656374222c0a20206170657274757265526571756972656d656e743a2061706572747572652d726571756972656d656e742c0a2020737570706f7274506f6c6963793a20747374722c0a20206c6f7373446973706f736974696f6e3a20747374722c0a7d0a0a636f72652d626c6f636b203d207b0a20206c6f63616c733a205b2a206c6f63616c2d7265665d2c0a20206e6f6465733a205b2a20636f72652d6e6f64655d2c0a2020726573756c743a20636f72652d657870722c0a7d0a0a636f72652d6e6f6465203d206c65742d6e6f6465202f20726571756972652d6e6f6465202f206566666563742d6e6f6465202f2067756172642d6e6f6465202f206272616e63682d6e6f6465202f0a202020202020202020202020666f722d6e6f6465202f206d617463682d6e6f6465202f2070726f6f662d6f626c69676174696f6e2d6e6f64650a0a6c65742d6e6f6465203d207b0a20206b696e643a20226c6574222c0a202062696e64696e673a206c6f63616c2d7265662c0a202076616c75653a20636f72652d657870722c0a7d0a726571756972652d6e6f6465203d207b0a20206b696e643a202272657175697265222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20206f6e4661696c7572653a20726571756972652d6661696c7572652d61726d2c0a7d0a726571756972652d6661696c7572652d61726d203d207465726d696e616c2d726571756972652d6661696c757265202f0a20202020202020202020202020202020202020202020636f6e74696e75652d6f6273747275637465642d726571756972652d6661696c7572650a7465726d696e616c2d726571756972652d6661696c757265203d207b0a20206b696e643a20227465726d696e616c222c0a2020726561736f6e3a206f62737472756374696f6e2d726561736f6e2c0a7d0a636f6e74696e75652d6f6273747275637465642d726571756972652d6661696c757265203d207b0a20206b696e643a2022636f6e74696e75654f627374727563746564222c0a2020726561736f6e3a206f62737472756374696f6e2d726561736f6e2c0a7d0a6f62737472756374696f6e2d726561736f6e203d207b0a2020726561736f6e4b696e643a20747374722c0a20207061796c6f61643a207b202a2074737472203d3e20636f72652d65787072207d2c0a7d0a6566666563742d6e6f6465203d207b0a20206b696e643a2022656666656374222c0a202062696e64696e673a206c6f63616c2d7265662c0a20206566666563743a20747374722c0a2020696e7075743a20636f72652d657870722c0a20206f62737472756374696f6e4d61703a207b202a206661696c7572652d6964656e74203d3e206f62737472756374696f6e2d61726d207d2c0a7d0a6f62737472756374696f6e2d61726d203d207b0a202062696e6465723a206c6f63616c2d7265662c0a202076616c75653a20636f72652d657870722c0a7d0a67756172642d6e6f6465203d207b0a20206b696e643a20226775617264222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20206f62737472756374696f6e3a20636f72652d657870722c0a7d0a6272616e63682d6e6f6465203d207b0a20206b696e643a20226272616e6368222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20207468656e3a20636f72652d626c6f636b2c0a2020656c73653a20636f72652d626c6f636b2c0a7d0a666f722d6e6f6465203d207b0a20206b696e643a2022666f72222c0a202062696e6465723a206c6f63616c2d7265662c0a2020697465723a20636f72652d657870722c0a2020626f756e643a20636f72652d626f756e642c0a2020626f64793a20636f72652d626c6f636b2c0a7d0a6d617463682d6e6f6465203d207b0a20206b696e643a20226d61746368222c0a20207363727574696e65653a20636f72652d657870722c0a202061726d733a205b2b206d617463682d626c6f636b2d61726d5d2c0a7d0a6d617463682d626c6f636b2d61726d203d207b0a2020636173653a20747374722c0a20203f2062696e6465723a206c6f63616c2d7265662c0a2020626f64793a20636f72652d626c6f636b2c0a7d0a70726f6f662d6f626c69676174696f6e2d6e6f6465203d207b0a20206b696e643a202270726f6f66222c0a2020636f6f7264696e6174653a20747374722c0a20207072656469636174653a20636f72652d7072656469636174652c0a7d0a0a636f72652d626f756e64203d206c69746572616c2d626f756e64202f20636f6f7264696e6174652d626f756e640a6c69746572616c2d626f756e64203d207b206b696e643a20226c69746572616c222c2076616c75653a2075696e74207d0a636f6f7264696e6174652d626f756e64203d207b206b696e643a2022636f6f7264696e617465222c207265663a2074737472207d0a0a3b20536861726564207265736f757263652d7265662c207368613235362d6469676573742c206661696c7572652d6964656e742c2061706572747572652d726571756972656d656e742c20616e640a3b20636f72652d747970652d7265662061726520646566696e6564206f6e636520696e2065646963742d636f6d6d6f6e2e6364646c2e0a0a3b202d2d2d2065646963742d6c61777061636b2e6364646c202d2d2d0a3b2065646963742d6c61777061636b2e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f7220746865204564696374206c61777061636b206d616e696665737420616e64206578706f727420737572666163652e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e204a534f4e20696e207468652070726f73652073706563730a3b2069732061207265766965772072656e646572696e672067656e6572617465642066726f6d207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a6c61777061636b2d6d616e6966657374203d207b0a202061706956657273696f6e3a202265646963742e6c61777061636b2f7631222c0a202069643a20747374722c0a202076657273696f6e3a20747374722c0a20206163636570746564436f72654162693a205b2b20747374725d2c0a2020646570656e64656e636965733a205b2a206c61777061636b2d6465705d2c202020202020202020203b20616379636c69632c206469676573742d6c6f636b6564202845444943542d4c41575041434b2d4441472d303031290a20206578706f7274733a207265736f757263652d7265662c0a20203f2074617267657441646170746572733a205b2b207461726765742d616461707465725d2c2020203b207265717569726564206f6e6c7920696620616e792072756e74696d6520656666656374206578697374730a20203f2068656c706572436f6d706f6e656e743a2065786563757461626c652d636f6d706f6e656e742c203b2065786563757461626c652068656c70657273206361727279207468656972206f776e2073616e64626f782b6675656c0a202076657269666965723a2076657269666965722c202020202020202020202020202020202020202020203b20636c61737369666965643a206465636c61726174697665206f722065786563757461626c650a2020636f6d7061746962696c6974793a207265736f757263652d7265662c0a2020636f6e666f726d616e636546697874757265436f727075733a207265736f757263652d7265662c0a7d0a0a3b2041207665726966696572206973206569746865722061206465636c617261746976652072756c6573657420286e6f2072756e74696d6529206f7220616e2065786563757461626c650a3b20636f6d706f6e656e742e20416e2065786563757461626c65207665726966696572204d55535420636172727920697473206f776e2073616e64626f7820616e64206675656c206d6f64656c2c0a3b20736f2074686520736368656d6120656e666f726365732074686174206e6f2065786563757461626c6520636f6d706f6e656e74206973206c65667420756e626f756e6465640a3b202845444943542d4142492d56455249464945522d424f554e442d303031292e0a7665726966696572203d206465636c617261746976652d7665726966696572202f2065786563757461626c652d76657269666965720a6465636c617261746976652d7665726966696572203d207b20636c6173733a20226465636c61726174697665222c2072756c657365743a207265736f757263652d726566207d0a65786563757461626c652d7665726966696572203d207b0a2020636c6173733a202265786563757461626c65222c0a2020636f6d706f6e656e743a207265736f757263652d7265662c0a202073616e64626f783a207265736f757263652d7265662c0a20206675656c4d6f64656c3a207265736f757263652d7265662c0a7d0a0a3b20416e792065786563757461626c6520636f6d706f6e656e7420697320626f756e64656420627920697473206f776e2073616e64626f78202b206675656c206d6f64656c2e0a65786563757461626c652d636f6d706f6e656e74203d207b0a2020636f6d706f6e656e743a207265736f757263652d7265662c0a202073616e64626f783a207265736f757263652d7265662c0a20206675656c4d6f64656c3a207265736f757263652d7265662c0a7d0a0a6c61777061636b2d646570203d207b2069643a20747374722c2076657273696f6e3a20747374722c206469676573743a207368613235362d646967657374207d0a0a3b20416461707465722073656c656374696f6e206b65797320534f4c454c59206f666620746865206469676573742d6c6f636b65642060616363657074656454617267657450726f66696c65600a3b20286974732060696460206973207468652070726f66696c652069643b206974732060646967657374602070696e73207468652065786163742070726f66696c652f76657273696f6e292e2054686572650a3b20617265206e6f20696e646570656e64656e7420646973706c617920737472696e6773207468617420636f756c64206469736167726565207769746820746865206c6f636b2c20736f20610a3b207265736f6c7665722063616e6e6f742062696e6420616e206164617074657220746f206f6e6520746172676574207768696c6520746865206c6f636b2070726f76657320616e6f746865720a3b202845444943542d4c41575041434b2d414441505445522d54415247455449522d303031292e0a7461726765742d61646170746572203d207b0a2020616363657074656454617267657450726f66696c653a207265736f757263652d7265662c202020203b206469676573742d6c6f636b65642c20617574686f72697461746976652073656c6563746f720a2020616363657074656454617267657449723a207265736f757263652d7265662c2020202020202020203b206469676573742d6c6f636b65640a2020616461707465723a207265736f757263652d7265662c0a7d0a0a3b20536861726564207479706573207265736f757263652d72656620616e64207368613235362d6469676573742061726520646566696e6564206f6e636520696e0a3b2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a3b202d2d2d206578706f72742073757266616365202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a6c61777061636b2d6578706f727473203d207b0a202074797065733a205b2a206578706f727465642d747970655d2c0a2020636f6e7374616e74733a205b2a206578706f727465642d636f6e7374616e745d2c0a20207075726546756e6374696f6e733a205b2a20707572652d66756e6374696f6e5d2c0a2020656666656374733a205b2a2073656d616e7469632d6566666563745d2c0a20206f62737472756374696f6e733a205b2a206f62737472756374696f6e2d6465665d2c0a20203b206b65796564206279206f7065726174696f6e2d70726f66696c6520636f6f7264696e61746520e2869220756e697175656e65737320656e666f726365640a20203b202845444943542d4142492d4f5050524f46494c452d554e495155452d303031290a20203b206f7065726174696f6e2d70726f66696c65207265636f7264732074686973206c61777061636b206578706f72747320286f707469632074656d706c6174657320746861740a20203b2060696d706c656d656e7473602f6070726f66696c656020636c6175736573207265736f6c766520616761696e7374292e206f7065726174696f6e2d70726f66696c652069730a20203b20646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c202845444943542d4142492d4f5050524f46494c452d534c4f542d303031292e0a20206f7065726174696f6e50726f66696c65733a207b202a2074737472203d3e206f7065726174696f6e2d70726f66696c65207d2c20203b206b6579656420627920636f6f7264696e6174650a7d0a0a6578706f727465642d7479706520202020203d207b20636f6f7264696e6174653a20747374722c20646566696e6974696f6e3a20636f72652d747970652d726566207d0a6578706f727465642d636f6e7374616e74203d207b20636f6f7264696e6174653a20747374722c20747970653a20636f72652d747970652d7265662c2076616c75653a20616e79207d0a0a3b204120707572652068656c7065722069732061206469736372696d696e6174656420756e696f6e2062792060736f75726365602c20736f2074686520736368656d6120697473656c660a3b2067756172616e7465657320616e20696d706c656d656e746174696f6e20657869737473202845444943542d4c41575041434b2d505552452d494d504c2d303031293a0a3b2020202d20226564696374223a20617574686f72656420696e2045646963742f436f72653b2074686520436f726520626f6479206973206361727269656420696e6c696e6520286861736865640a3b20202020207769746820746865206578706f72742073757266616365292e2054686520736368656d61207265717569726573207468652060626f647960206669656c642e0a3b2020202d2022636f6d706f6e656e74223a20696d706c656d656e746564206f7574736964652045646963743b2063617272696573206e6f20696e6c696e6520626f647920616e6420696e73746561640a3b20202020206361727269657320697473206f776e206469676573742d6c6f636b65642060696d706c656d656e746174696f6e60202873616e64626f78202b206675656c292e20497420646f65730a3b20202020206e6f7420646570656e64206f6e20746865206f7074696f6e616c206d616e69666573742d6c6576656c2068656c706572436f6d706f6e656e742e0a707572652d66756e6374696f6e203d2065646963742d707572652d66756e6374696f6e202f20636f6d706f6e656e742d707572652d66756e6374696f6e0a0a707572652d66756e6374696f6e2d636f6d6d6f6e203d20280a2020636f6f7264696e6174653a20747374722c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020706172616d6574657254797065733a205b2a20636f72652d747970652d7265665d2c2020202020203b20616c6c20626f756e6465640a202072657475726e547970653a20636f72652d747970652d7265662c20202020202020202020202020203b20626f756e6465640a2020636f737454656d706c6174653a20747374722c0a202064657465726d696e69736d436c6173733a2022746f74616c22202f2022746f74616c2d776974682d74797065642d646961676e6f73746963222c0a290a0a65646963742d707572652d66756e6374696f6e203d207b0a2020707572652d66756e6374696f6e2d636f6d6d6f6e2c0a2020736f757263653a20226564696374222c0a2020626f64793a20636f72652d666e2d626f64792c2020202020202020202020202020202020202020203b20696e6c696e652c20686173682d7369676e69666963616e740a7d0a0a636f6d706f6e656e742d707572652d66756e6374696f6e203d207b0a2020707572652d66756e6374696f6e2d636f6d6d6f6e2c0a2020736f757263653a2022636f6d706f6e656e74222c0a20203b20746865206469676573742d6c6f636b656420636f6d706f6e656e7420696d706c656d656e74696e6720746869732068656c7065722e2052657175697265642061742074686520736368656d610a20203b206c6576656c20736f206120636f6d706f6e656e742068656c7065722063616e206e657665722076616c696461746520776974686f7574206120686173682d626f756e642c0a20203b2073616e64626f782b6675656c2d64657363726962656420696d706c656d656e746174696f6e202845444943542d4c41575041434b2d505552452d494d504c2d303031292e0a2020696d706c656d656e746174696f6e3a2065786563757461626c652d636f6d706f6e656e742c0a7d0a0a3b20636f72652d666e2d626f647920697320646566696e65642062792065646963742d636f72652e6364646c20616e6420617373656d626c656420776974682074686973206c61777061636b0a3b20736368656d612e2049742069732061207075726520436f72652066756e6374696f6e20626f64792c206e6f7420616e206566666563742d63617061626c6520636f72652d626c6f636b2e0a0a73656d616e7469632d656666656374203d207b0a2020636f6f7264696e6174653a20747374722c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020696e707574547970653a20636f72652d747970652d7265662c2020202020202020202020202020203b20626f756e6465640a20206f7574707574547970653a20636f72652d747970652d7265662c20202020202020202020202020203b20626f756e6465640a2020657865637574696f6e436c6173733a202270726f6f664f6e6c7922202f202272756e74696d65222c2020203b206f7274686f676f6e616c20746f207772697465436c6173730a20206566666563744b696e6448696e743a206566666563742d6b696e642c0a2020666f6f747072696e744f626c69676174696f6e3a20747374722c0a2020636f73744f626c69676174696f6e3a20747374722c0a20206566666563744661696c757265733a207b202a206661696c7572652d6964656e74203d3e206566666563742d6661696c7572652d626f6479207d2c20203b206b6579656420627920636f6f7264696e6174653b20756e697175650a20206775617264537570706f72743a20626f6f6c2c0a7d0a0a6f62737472756374696f6e2d646566203d207b0a2020636f6f7264696e6174653a20747374722c0a2020617574686f72697479436c6173733a20617574686f726974792d636c6173732c0a20207061796c6f6164536368656d613a20636f72652d747970652d7265662c20202020202020202020203b2074797065642c20626f756e64656420286d617920626520656d707479207265636f7264290a7d0a0a3b206566666563742d6661696c7572652d626f64792c206566666563742d6b696e642c20617574686f726974792d636c6173732c20616e6420636f72652d747970652d7265662061726520646566696e65640a3b206f6e636520696e2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a3b202d2d2d2065646963742d6c61777061636b2d616461707465722e6364646c202d2d2d0a3b2065646963742d6c61777061636b2d616461707465722e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f72206f6e6520646972656374206465636c61726174697665206c61777061636b2074617267657420616461707465722e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a3b0a3b2054686520656e636c6f73696e67206c61777061636b206d616e69666573742073656c6563747320746865206578616374207461726765742070726f66696c652c207461726765742049522c0a3b20616e642061646170746572207265736f75726365206469676573742e2054686f7365206964656e74697469657320617265206e6f7420726570656174656420686572652e0a0a6c61777061636b2d61646170746572203d207b0a202061706956657273696f6e3a202265646963742e6c61777061636b2d616461707465722f7631222c0a2020636c6173733a20226465636c61726174697665222c0a20206f7065726174696f6e50726f66696c65733a207b0a202020202a2074737472203d3e206c61777061636b2d616461707465722d6f7065726174696f6e2d70726f66696c650a20207d2c0a2020656666656374496d706c656d656e746174696f6e733a207b0a202020202a2074737472203d3e206c61777061636b2d616461707465722d6566666563740a20207d2c0a2020627564676574733a207b0a202020202a2074737472203d3e206c61777061636b2d616461707465722d6275646765740a20207d2c0a7d0a0a3b204b657973206172652063616e6f6e6963616c206c61777061636b206f7065726174696f6e2d70726f66696c6520636f6f7264696e617465732e0a6c61777061636b2d616461707465722d6f7065726174696f6e2d70726f66696c65203d207b0a2020636f72653a20747374722c0a202073656d616e746963456666656374733a205b2b20747374725d2c0a7d0a0a3b204b657973206172652063616e6f6e6963616c206c61777061636b2073656d616e7469632d65666665637420636f6f7264696e617465732e20466f6f747072696e742c20636f73742c20616e640a3b206661696c757265206669656c6473206d7573742065786163746c792064697363686172676520746865206d61746368696e67206578706f72746564206566666563742e0a6c61777061636b2d616461707465722d656666656374203d207b0a2020746172676574496e7472696e7369633a20747374722c0a2020746172676574436f6e66696775726174696f6e3a207265736f757263652d7265662c0a20207772697465436c6173733a206c61777061636b2d616461707465722d77726974652d636c6173732c0a2020666f6f747072696e744f626c69676174696f6e3a20747374722c0a2020636f73744f626c69676174696f6e3a20747374722c0a20206661696c7572654d617070696e67733a207b202a206661696c7572652d6964656e74203d3e2074737472207d2c0a7d0a0a3b204b657973206172652063616e6f6e6963616c206578706f7274656420636f73742d6f626c69676174696f6e20636f6f7264696e617465732e0a6c61777061636b2d616461707465722d627564676574203d207b0a20206d617853746570733a2075696e742c0a20206d6178416c6c6f636174656442797465733a2075696e742c0a20206d61784f757470757442797465733a2075696e742c0a7d0a0a6c61777061636b2d616461707465722d77726974652d636c617373203d20226e6f6e6522202f20227265616422202f202263726561746522202f2022656e7375726522202f0a20202020202020202020202020202020202020202020202020202020202022617070656e6422202f20226d6f6469667922202f202264656c657465220a0a3b206661696c7572652d6964656e7420697320646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c2e0a0a3b202d2d2d2065646963742d7461726765742d70726f66696c652e6364646c202d2d2d0a3b2065646963742d7461726765742d70726f66696c652e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f7220746865204564696374207461726765742070726f66696c65206d616e69666573742e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76310a3b202873656520535045435f636f6e74696e75756d2d636f6e74726163742d62756e646c652d76312e6d64292e204a534f4e20696e207468652070726f736520737065637320697320610a3b207265766965772072656e646572696e672067656e6572617465642066726f6d207468697320736368656d613b2074686973204344444c206973207468652073696e676c6520736f757263650a3b206f66207472757468202845444943542d4142492d4e4f4455502d303031292e0a0a7461726765742d70726f66696c652d6d616e6966657374203d207b0a202061706956657273696f6e3a202265646963742e7461726765742d70726f66696c652f7631222c0a202069643a20747374722c202020202020202020202020202020202020202020202020203b20652e672e20226563686f2e64706f220a202076657273696f6e3a20747374722c20202020202020202020202020202020202020203b20652e672e202231220a20206163636570746564436f72654162693a205b2b20747374725d2c20202020202020203b20652e672e205b2265646963742e636f72652f7631225d0a0a2020696e7472696e736963733a207265736f757263652d7265662c0a2020696e7472696e7369634e616d6573706163653a20747374722c0a20203b207075626c697368657320746869732070726f66696c652773206f7065726174696f6e2d70726f66696c65207265636f72647320286f707469632074656d706c6174657320746861740a20203b206070726f66696c65602f60696d706c656d656e74736020636c6175736573207265736f6c766520616761696e7374292e205265666572656e63657320616e0a20203b206f7065726174696f6e2d70726f66696c65732d646f63756d656e74202845444943542d4142492d4f5050524f46494c452d534c4f542d303031292e0a20206f7065726174696f6e50726f66696c65733a207265736f757263652d7265662c0a2020666f6f747072696e74416c67656272613a207265736f757263652d7265662c0a2020636f7374416c67656272613a207265736f757263652d7265662c0a202074617267657449723a207265736f757263652d7265662c0a20206f62737472756374696f6e5461786f6e6f6d793a207265736f757263652d7265662c0a202076657269666965723a207265736f757263652d7265662c0a20206c6f77657265723a207265736f757263652d7265662c0a202073616e64626f783a207265736f757263652d7265662c0a20206675656c4d6f64656c3a207265736f757263652d7265662c0a0a20203b206669656c647320746865206c616e67756167652073706563207265717569726573206f662065766572792070726f66696c650a202062756e646c6550726f66696c653a207265736f757263652d7265662c0a202067656e657261746564417274696661637450726f66696c65733a205b2a207265736f757263652d7265665d2c0a202063616e6f6e6963616c456e636f64696e6752756c65733a207265736f757263652d7265662c0a20203b20412070726f66696c65207468617420616363657074732074686520646972656374206465636c61726174697665206c61777061636b2d6164617074657220414249206e616d65732069740a20203b2065786163746c79206f6e63652e2050726f66696c6573207468617420646f206e6f7420636f6e73756d65206c61777061636b206164617074657273206c6561766520746869730a20203b206f7074696f6e616c20736c6f7420616273656e74206f7220656d7074792e0a20203f2061636365707465644c61777061636b416461707465724162693a205b5d202f205b2265646963742e6c61777061636b2d616461707465722f7631225d2c0a2020646961676e6f737469634162693a207265736f757263652d7265662c0a0a20203b206170706c69636174696f6e20646f637472696e650a20206170706c69636174696f6e4d6f64656c3a202261746f6d6963222c0a202072656164436f6e73697374656e63793a20226170706c69636174696f6e2d736e617073686f7422202f20747374722c0a202067756172644576616c756174696f6e3a2022707265636f6d6d69742d61746f6d696322202f20747374722c0a20206f62737472756374696f6e526f6c6c6261636b3a20226e6f2d76697369626c652d6566666563747322202f20747374722c0a20206d756c74695461726765743a20626f6f6c2c0a20203b207768657468657220746865207461726765742063616e206576616c7561746520707265636f6d6d697420706f7374636f6e646974696f6e20286067756172616e746565602920636865636b730a20203b20696e73696465207468652061746f6d6963206170706c69636174696f6e20756e6974202845444943542d5441524745542d504f5354434f4e442d303031290a2020706f7374636f6e646974696f6e537570706f72743a20626f6f6c2c0a0a202064657465726d696e6973746963457865637574696f6e3a207265736f757263652d7265662c0a2020636f6e666f726d616e636546697874757265436f727075733a207265736f757263652d7265662c0a7d0a0a3b20536861726564207479706573207265736f757263652d72656620616e64207368613235362d6469676573742061726520646566696e6564206f6e636520696e0a3b2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d6120627920746865206275696c640a3b202845444943542d4142492d4e4f4455502d303031292e205468657920617265206e6f74207265646566696e656420686572652e0a0a3b202d2d2d20696e7472696e736963207369676e6174757265202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a3b20546865206172746966616374207265666572656e63656420627920746865206d616e696665737427732060696e7472696e7369637360207265736f757263652d726566206973207468650a3b20696e7472696e7369632d7369676e617475726520636f7270757320646f63756d656e742062656c6f772e20497473206c61796f757420697320666978656420736f2074776f0a3b20696e646570656e64656e742070726f66696c65732076616c69646174652f686173682074686520636f72707573206964656e746963616c6c790a3b202845444943542d4142492d494e5452494e534943532d444f432d303031292e0a0a3b20696e7472696e736963732069732061204d4150206b6579656420627920636f6f7264696e6174652c20736f2074686520736368656d6120697473656c6620656e666f726365730a3b20636f6f7264696e61746520756e697175656e6573732e20412070726f766964657220726563656976657320746865207265736f6c76656420636f7270757320617320610a3b206469676573742d626f756e642073656d616e74696320696e70757420616e64207265736f6c76657320636f6f7264696e617465732077697468696e20746861742061727469666163742e0a3b2045616368206d6170206b6579204d55535420657175616c20697473207265636f726427732060636f6f7264696e61746560206669656c640a3b202845444943542d4142492d494e5452494e5349432d554e495155452d303031292e0a696e7472696e736963732d646f63756d656e74203d207b0a202061706956657273696f6e3a202265646963742e7461726765742d70726f66696c652e696e7472696e736963732f7631222c0a2020696e7472696e736963733a207b202a2074737472203d3e20696e7472696e736963207d2c0a7d0a0a3b20546865206172746966616374207265666572656e63656420627920746865206d616e6966657374277320606f7065726174696f6e50726f66696c657360207265736f757263652d7265662e0a3b206f7065726174696f6e2d70726f66696c65202f206f707469632d74656d706c6174652061726520646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c2e204b657965642062790a3b20636f6f7264696e61746520736f207265736f6c7574696f6e2063616e2774207069636b206265747765656e2074776f2073616d652d636f6f7264696e6174652070726f66696c65730a3b202845444943542d4142492d4f5050524f46494c452d534c4f542d3030312c2045444943542d4142492d4f5050524f46494c452d554e495155452d303031292e0a6f7065726174696f6e2d70726f66696c65732d646f63756d656e74203d207b0a202061706956657273696f6e3a202265646963742e7461726765742d70726f66696c652e6f7065726174696f6e2d70726f66696c65732f7631222c0a202070726f66696c65733a207b202a2074737472203d3e206f7065726174696f6e2d70726f66696c65207d2c0a7d0a0a3b2041207479706564207072652d6c6f776572696e67207175657374696f6e20746861742063616e2062652070726f706f73656420627920576174736f6e206f7220616e206167656e7420616e640a3b20636865636b65642062792074686520636f6d70696c65722e2049742069732063616e6f6e6963616c2d43424f5220656e636f64656420756e6465720a3b206065646963742e6c6f776572696e672d726571756972656d656e74732f7631603b2074686520636f6d70696c657220636865636b7320746869732061727469666163742c206e6f74207468650a3b2070726f736520746861742070726f64756365642069742e0a6c6f776572696e672d726571756972656d656e7473203d207b0a202061706956657273696f6e3a202265646963742e6c6f776572696e672d726571756972656d656e74732f7631222c0a20206f7065726174696f6e50726f66696c653a20747374722c0a202073656d616e746963456666656374733a205b2a2073656d616e7469632d6566666563742d726571756972656d656e745d2c0a202072657175697265645772697465436c61737365733a205b2a2077726974652d636c6173735d2c0a202067756172644b696e64733a205b2a2067756172642d6b696e645d2c0a202061746f6d69636974793a2061746f6d69636974792d726571756972656d656e742c0a2020706f7374636f6e646974696f6e537570706f72743a20626f6f6c2c0a20206f62737472756374696f6e436f6f7264696e617465733a205b2a20747374725d2c0a2020666f6f747072696e744f626c69676174696f6e733a205b2a20747374725d2c0a2020636f73744f626c69676174696f6e733a205b2a20747374725d2c0a20206f70746963436f6e74726163743a20747374722c0a7d0a0a73656d616e7469632d6566666563742d726571756972656d656e74203d207b0a2020636f6f7264696e6174653a20747374722c0a20207772697465436c6173733a2077726974652d636c6173732c0a202067756172644b696e64733a205b2a2067756172642d6b696e645d2c0a20206f62737472756374696f6e436f6f7264696e617465733a205b2a20747374725d2c0a2020666f6f747072696e744f626c69676174696f6e733a205b2a20747374725d2c0a2020636f73744f626c69676174696f6e733a205b2a20747374725d2c0a7d0a0a77726974652d636c617373203d20226e6f6e6522202f20227265616422202f202263726561746522202f2022656e7375726522202f2022617070656e6422202f0a2020202020202020202020202020227265706c61636522202f202264656c65746522202f20747374720a67756172642d6b696e64203d2022707265636f6d6d69742d61746f6d696322202f20747374720a61746f6d69636974792d726571756972656d656e74203d202261746f6d696322202f20747374720a0a3b20412067656e75696e6520756e696f6e3a207075726520636f6e7374727563746f7273206361727279206e6f20656666656374206b696e64206f72206661696c757265733b206566666563740a3b20696e7472696e73696373206d757374202845444943542d5441524745542d494e5452494e5349432d434c4153532d303031292e2054686520736368656d6120656e666f7263657320746869732c0a3b206e6f74206120636f6d6d656e742e0a0a3b2054686520696e7472696e736963277320636f6f7264696e6174652069732074686520696e7472696e73696373206d6170204b45592c206e6f7420612076616c7565206669656c642c20736f207468650a3b206b657920616e6420636f6f7264696e6174652063616e206e65766572206469736167726565202845444943542d4142492d494e5452494e5349432d554e495155452d303031292e0a696e7472696e736963203d20707572652d696e7472696e736963202f206566666563742d696e7472696e7369630a0a707572652d696e7472696e736963203d207b0a2020696e7472696e736963436c6173733a202270757265222c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020617267756d656e7454797065733a205b2a20636f72652d747970652d7265665d2c0a202072657475726e547970653a20636f72652d747970652d7265662c0a20206775617264537570706f72743a2066616c73652c0a2020666f6f747072696e7454656d706c6174653a20747374722c0a2020636f737454656d706c6174653a20747374722c0a20207772697465436c6173733a20226e6f6e65222c0a7d0a0a6566666563742d696e7472696e736963203d207b0a2020696e7472696e736963436c6173733a2022656666656374222c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020617267756d656e7454797065733a205b2a20636f72652d747970652d7265665d2c0a202072657475726e547970653a20636f72652d747970652d7265662c0a20206566666563744b696e643a206566666563742d6b696e642c0a20203b206d6170206b65796564206279206661696c75726520636f6f7264696e61746520286661696c7572652d6964656e74293b20746865206661696c75726520636f6f7264696e6174652069730a20203b20746865206b65792c206e6f7420612076616c7565206669656c642c20736f20756e697175656e657373206973207374727563747572616c0a20203b202845444943542d4142492d4641494c5552452d554e495155452d303031292e0a20206566666563744661696c757265733a207b202a206661696c7572652d6964656e74203d3e206566666563742d6661696c7572652d626f6479207d2c0a20206775617264537570706f72743a20626f6f6c2c0a2020666f6f747072696e7454656d706c6174653a20747374722c0a2020636f737454656d706c6174653a20747374722c0a20207772697465436c6173733a20227265616422202f202263726561746522202f2022656e7375726522202f2022617070656e6422202f20227265706c61636522202f0a20202020202020202020202020202264656c65746522202f2022637573746f6d222c0a202063616e5061727469636970617465496e41746f6d696347756172643a20626f6f6c2c0a7d0a0a3b206566666563742d6661696c7572652d626f64792c206566666563742d6b696e642c20617574686f726974792d636c6173732c20616e6420636f72652d747970652d7265662061726520646566696e65640a3b206f6e636520696e2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a3b202d2d2d2065646963742d617574686f726974792d66616374732e6364646c202d2d2d0a3b2065646963742d617574686f726974792d66616374732e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f722074686520666972737420636f6d70696c65722d636f6e7465787420617574686f726974792d666163747320646f63756d656e742e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a3b0a3b205468697320736368656d6120697320617373656d626c656420776974682065646963742d636f6d6d6f6e2e6364646c20736f20736f757263652e6469676573742075736573207468650a3b20736861726564207368613235362d6469676573742074797065642076616c75652e204a534f4e2069732061207265766965772f696e7075742072656e646572696e673a206974730a3b20607368613235363a3c3634206865783e6020736f75726365206469676573742069732070726f6a656374656420746f205b60736861323536602c203332207261772062797465735d206f6e0a3b2074686520776972652c20616e64206974732066616374206172726179732070726f6a65637420746f2074686520636f6f7264696e6174652d6b65796564206d6170732062656c6f772e0a0a617574686f726974792d6661637473203d207b0a202061706956657273696f6e3a202265646963742e617574686f726974792d66616374732f7631222c0a2020736f757263653a20617574686f726974792d666163742d736f757263652c0a20206f7065726174696f6e50726f66696c65733a207b202a2074737472203d3e20617574686f726974792d6f7065726174696f6e2d70726f66696c652d66616374207d2c0a20206566666563745772697465436c61737365733a207b202a2074737472203d3e20617574686f726974792d77726974652d636c617373207d2c0a2020627564676574733a207b202a2074737472203d3e20617574686f726974792d6275646765742d66616374207d2c0a7d0a0a617574686f726974792d666163742d736f75726365203d207b0a20206b696e643a20226c61777061636b22202f202274617267657450726f66696c65222c0a2020636f6f7264696e6174653a20747374722c0a20206469676573743a207368613235362d6469676573742c0a7d0a0a3b20546865206d6170206b65792069732074686520736f75726365206f7065726174696f6e2d70726f66696c6520636f6f7264696e6174652e204974206973206e6f7420726570656174656420696e0a3b207468652076616c75652c20736f2061206b657920616e6420656d62656464656420636f6f7264696e6174652063616e6e6f742064697361677265652e20416c6c6f7765642077726974650a3b20636c61737365732061726520612063616e6f6e6963616c206d61702d7365743a2074686520636c6173732069732074686520756e69717565206b657920616e64206e756c6c206973207468650a3b20756e6974206d61726b65722e2043616e6f6e6963616c2043424f52206669786573206b6579206f7264657220776974686f75742061207365636f6e64206f72646572696e672072756c652e0a617574686f726974792d6f7065726174696f6e2d70726f66696c652d66616374203d207b0a2020636f72653a20747374722c0a2020616c6c6f7765645772697465436c61737365733a207b202a20617574686f726974792d77726974652d636c617373203d3e206e756c6c207d2c0a7d0a0a3b20546865206566666563745772697465436c6173736573206d6170206b6579206973207468652073656d616e7469632065666665637420636f6f7264696e6174652e2054686520627564676574730a3b206d6170206b65792069732074686520736f757263652062756467657420636f6f7264696e6174652e2043616e6f6e6963616c2043424f52206d61702d6b657920756e697175656e6573730a3b206d616b6573206475706c6963617465206661637420636f6f7264696e61746573207374727563747572616c6c7920756e726570726573656e7461626c652e0a617574686f726974792d6275646765742d66616374203d207b0a20206d617853746570733a2075696e742c0a20206d6178416c6c6f636174656442797465733a2075696e742c0a20206d61784f757470757442797465733a2075696e742c0a7d0a0a3b20417574686f726974794661637473446f63756d656e7420763120696e74656e74696f6e616c6c792061636365707473206f6e6c792074686520777269746520636c6173736573207468650a3b2063757272656e7420636f6d70696c6572206d6f64656c2063616e20636f6e73756d652e2060637573746f6d602069732074686520736f6c6520763120637573746f6d207370656c6c696e673b0a3b20617262697472617279207461726765742d70726f66696c6520657874656e73696f6e20737472696e677320646f206e6f7420656e746572207468697320636f6d70696c657220706174682e0a617574686f726974792d77726974652d636c617373203d20226e6f6e6522202f20227265616422202f202263726561746522202f2022656e7375726522202f2022617070656e6422202f0a202020202020202020202020202020202020202020202020227265706c61636522202f202264656c65746522202f2022637573746f6d220a0a3b202d2d2d2065646963742d7461726765742d69722e6364646c202d2d2d0a3b20535044582d4c6963656e73652d4964656e7469666965723a204170616368652d322e300a3b2065646963742d7461726765742d69722e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f72207468652045646963742d6f776e65642054617267657420495220617274696661637420656e76656c6f70652e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a3b0a3b205468697320736368656d6120697320617373656d626c656420776974682065646963742d636f6d6d6f6e2e6364646c20616e642065646963742d636f72652e6364646c2e2049740a3b2064656c696265726174656c792072657573657320436f72652065787072657373696f6e732c20707265646963617465732c20627564676574732c206c6f63616c207265666572656e6365732c0a3b206f62737472756374696f6e20726561736f6e732c20616e64206f62737472756374696f6e2061726d7320736f2074686520736368656d61206d617463686573207468652076616c75650a3b20656d6974746564206279207468652063616e6f6e6963616c2054617267657420495220656e636f64657220726174686572207468616e20726573746174696e672074686f73652074797065732e0a3b2049742064657363726962657320746865207374727563747572616c207368617065206f662076616c6964206c6f776572696e672d70726f6475636564206172746966616374732e205468650a3b206c6f776572696e6720616e6420656e636f64657220636f6e7472616374732073657061726174656c7920656e666f7263652073656d616e746963206964656e7469666965722072756c65730a3b20616e642063616e6f6e6963616c206f72646572696e672f64656475706c69636174696f6e20666f72207365742d6c696b652076616c7565732e0a0a3b2054617267657420495220656e636f64696e672072656a6563747320616e20656d707479207461726765742d70726f66696c6520636f6f7264696e617465206265666f72652062797465730a3b2065786973742c20736f207468697320726f6f74207469676874656e732074686520736861726564207374727563747572616c207265736f757263652d726566206163636f7264696e676c792e0a7461726765742d69722d7265736f757263652d726566203d207b0a202069643a2074737472202e7265676578702022283f73292e2b222c0a20206469676573743a207368613235362d6469676573742c0a7d0a0a7461726765742d69722d6172746966616374203d207461726765742d69722d636c6f7365642d6172746966616374202f207461726765742d69722d6c65676163792d61727469666163740a0a7461726765742d69722d61727469666163742d636f6d6d6f6e203d20280a20206b696e643a202274617267657449724172746966616374222c0a2020646f6d61696e3a20747374722c0a202074617267657450726f66696c653a207461726765742d69722d7265736f757263652d7265662c0a2020736f75726365436f7265436f6f7264696e6174653a2074737472202e7265676578702022283f73292e2b222c0a290a0a7461726765742d69722d636c6f7365642d6172746966616374203d207b0a20207461726765742d69722d61727469666163742d636f6d6d6f6e2c0a202073656d616e746963436c6f737572653a207461726765742d69722d73656d616e7469632d636c6f737572652c0a2020696e74656e74733a207b202a2074737472203d3e207461726765742d69722d696e74656e74207d2c0a7d0a0a7461726765742d69722d6c65676163792d6172746966616374203d207b0a20207461726765742d69722d61727469666163742d636f6d6d6f6e2c0a2020696e74656e74733a207b202a2074737472203d3e207461726765742d69722d6c65676163792d696e74656e74207d2c0a7d0a0a7461726765742d69722d73656d616e7469632d636c6f73757265203d207b0a2020736f75726365436f72653a207461726765742d69722d7265736f757263652d7265662c0a20206c61777061636b733a205b2a207461726765742d69722d7265736f757263652d7265665d2c0a7d0a0a7461726765742d69722d696e74656e74203d207b0a20207461726765742d69722d696e74656e742d636f6d6d6f6e2c0a20203f2062617369733a20636f72652d657870722c0a7d0a0a7461726765742d69722d6c65676163792d696e74656e74203d207b0a20207461726765742d69722d696e74656e742d636f6d6d6f6e2c0a7d0a0a7461726765742d69722d696e74656e742d636f6d6d6f6e203d20280a20206f7065726174696f6e50726f66696c653a20747374722c0a2020696e707574436f6e73747261696e74733a205b2a20696e7075742d636f6e73747261696e745d2c0a2020636f72654576616c756174696f6e4275646765743a20636f72652d6275646765742c0a2020726571756972656d656e74733a205b2a207461726765742d69722d726571756972656d656e745d2c0a202073746570733a205b2a207461726765742d69722d737465705d2c0a2020726573756c743a20636f72652d657870722c0a290a0a7461726765742d69722d726571756972656d656e74203d207b0a202069643a20747374722c0a20207072656469636174653a20636f72652d7072656469636174652c0a20206f6e4661696c7572653a20726571756972652d6661696c7572652d61726d2c0a7d0a0a7461726765742d69722d73746570203d207b0a202069643a20747374722c0a202062696e64696e673a206c6f63616c2d7265662c0a20206566666563743a20747374722c0a2020746172676574496e7472696e7369633a20747374722c0a2020696e7075743a20636f72652d657870722c0a20206f62737472756374696f6e4661696c757265733a205b2a206661696c7572652d6964656e745d2c0a20206f62737472756374696f6e41726d733a207b202a206661696c7572652d6964656e74203d3e206f62737472756374696f6e2d61726d207d2c0a7d0a", - "rawSha256": "a5d5ea82a9e64aa78c4a44204d3e8919c1c590febb967f1d31639fdc2a20a96c" + "bytesHex": "3b20535044582d4c6963656e73652d4964656e7469666965723a204170616368652d322e300a3b2065646963742d70726f76696465722d636f6e7472616374732e6364646c0a3b2047656e6572617465642066726f6d2045646963742d6f776e65642041424920667261676d656e74732e20444f204e4f5420454449542e0a0a3b202d2d2d2065646963742d636f6d6d6f6e2e6364646c202d2d2d0a3b2065646963742d636f6d6d6f6e2e6364646c0a3b20536861726564204344444c20747970657320666f722074686520456469637420414249732c20646566696e6564204f4e4345206865726520736f20746865792063616e6e6f742064726966740a3b202845444943542d4142492d4e4f4455502d303031292e2054776f2067726f7570733a0a3b2020202d207265736f757263652d7265662c207368613235362d6469676573742c206566666563742d6661696c7572652d626f64792c206566666563742d6b696e642c20617574686f726974792d636c6173732c0a3b2020202020636f72652d747970652d7265663a20617373656d626c656420776974682065646963742d7461726765742d70726f66696c652e6364646c20616e640a3b202020202065646963742d6c61777061636b2e6364646c20627920746865206275696c643b2074686f736520736368656d617320646f206e6f74207265646566696e65207468656d2e0a3b2020202d206f7065726174696f6e2d70726f66696c652c206f707469632d74656d706c6174652c2061706572747572652d726571756972656d656e7420616e6420746865697220726566733a0a3b2020202020636f6e73756d65642062792074686520436f72652f6f70746963206c61796572202865646963742d636f72652e6364646c2920616e64207265666572656e636564206279207468650a3b20202020206c616e67756167652f7461726765742d70726f66696c652073706563732e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a0a3b2041206e6f726d617469766520737562636f6d706f6e656e74207265666572656e636564206279206964656e7469747920706c7573206469676573742e204d616e696665737473206e657665720a3b20656d626564207468656972206f776e2073656c662d64696765737420696e20746865697220707265696d616765202845444943542d434f52452d53454c46484153482d303031292e0a7265736f757263652d726566203d207b2069643a20747374722c206469676573743a207368613235362d646967657374207d0a0a3b20446967657374732061726520617574686f726974617469766520617320747970656420627974652076616c7565732c206e657665722068657820737472696e67732e20526576696577204a534f4e0a3b2072656e64657273207468697320617320227368613235363a3c3634206c6f77657263617365206865783e22202845444943542d4449474553542d574952452d303031292e0a7368613235362d646967657374203d205b20616c676f726974686d3a2022736861323536222c2062797465733a2062737472202e73697a65203332205d0a0a3b2041206e616d6564206c6f772d6c6576656c206661696c75726520616e206566666563742063616e2072616973652e2054686520736f75726365206f62737472756374696f6e206d61700a3b2062696e64732069742028627920636f6f7264696e6174652920616e6420636f6e73747275637473206120747970656420646f6d61696e206f62737472756374696f6e2066726f6d206974730a3b207061796c6f6164202845444943542d4142492d4641494c5552452d4e414d45442d303031292e0a3b20416e20656666656374277320606566666563744661696c7572657360206c697374204d555354206861766520756e697175652060636f6f7264696e61746560733a2073696e6365207468650a3b206f62737472756374696f6e206d6170206973206b6579656420627920636f6f7264696e6174652c2074776f206661696c757265732073686172696e67206120636f6f7264696e61746520286576656e0a3b207769746820646966666572656e7420617574686f72697479436c6173732f7061796c6f61645479706529206d616b652065786861757374697665206d617070696e6720616e642062696e6465720a3b20747970696e6720616d626967756f757320616e64206172652072656a6563746564202845444943542d4142492d4641494c5552452d554e495155452d303031292e0a3b0a3b2045666665637473206361727279207468656972206661696c757265732061732061206d617020607b206661696c7572652d6964656e74203d3e206566666563742d6661696c7572652d626f6479207d600a3b202873656520746865207461726765742f6c61777061636b2065666665637420736368656d6173292e20546865206661696c75726520636f6f7264696e61746520697320746865206d61700a3b204b45592c20736f206974206973206e6f7420726570656174656420696e2074686520626f647920616e642063616e6e6f74206469736167726565207769746820746865206b65792e0a6566666563742d6661696c7572652d626f6479203d207b0a2020617574686f72697479436c6173733a20617574686f726974792d636c6173732c0a20207061796c6f6164547970653a20636f72652d747970652d7265662c202020202020202020202020203b2074797065642c20626f756e64656420286d617920626520656d707479207265636f7264290a7d0a0a3b2041206661696c75726520636f6f7264696e617465206d7573742062652061206261726520456469637420606964656e746020286c65747465722f756e64657273636f7265207468656e0a3b206c6574746572732f6469676974732f756e64657273636f7265732920414e44206d757374206e6f742062652061207265736572766564206b6579776f72642028652e672e2060656c7365602c0a3b20606261736973602c20607768657265602c206072657175697265602c2060666f72602c2060696660292e2054686520736f75726365206f62737472756374696f6e2d6d6170204c4853206f6e6c790a3b20616363657074732061206e6f6e2d6b6579776f726420606964656e74602c20736f20612068797068656e2f646f742f6b6579776f726420636f6f7264696e61746520776f756c642062650a3b204142492d76616c69642079657420696d706f737369626c6520746f206d617020657868617573746976656c7920696e20736f757263652e20546865207265676578206361707475726573207468650a3b206c65786963616c2073686170653b206b6579776f7264206578636c7573696f6e20697320616e206164646974696f6e616c2076616c69646174696f6e2072756c650a3b202845444943542d4142492d4641494c5552452d4944454e542d303031292e0a6661696c7572652d6964656e74203d2074737472202e72656765787020225b412d5a612d7a5f5d5b412d5a612d7a302d395f5d2a220a0a6566666563742d6b696e64203d20227265616422202f202263726561746522202f2022656e7375726522202f20227265706c61636522202f202264656c65746522202f0a202020202020202020202020202022617070656e6422202f202272656475636522202f202273656d616e7469632e656d697422202f2022637573746f6d220a0a617574686f726974792d636c617373203d2022646f6d61696e4d61707061626c6522202f20227061727469636970616e744f776e656422202f2022696e746567726974794661756c7422202f0a202020202020202020202020202020202020227265736f757263654661756c7422202f2022696e7465726e616c4661756c74220a0a636f72652d747970652d726566203d20747374722020203b2063616e6f6e6963616c20436f7265207479706520636f6f7264696e6174650a0a3b20416e206f7065726174696f6e2070726f66696c6520737570706c69657320746865206f707469632074656d706c617465206120436f726520696e74656e74207265736f6c766573206974730a3b206f707469634b696e642f626f756e646172794b696e642f737570706f7274506f6c6963792f6c6f7373446973706f736974696f6e2066726f6d2e205461726765742070726f66696c657320616e640a3b206c61777061636b73207075626c6973682074686573652061732061206d617020607b20636f6f7264696e617465203d3e206f7065726174696f6e2d70726f66696c65207d602c20736f207468650a3b20636f6f7264696e61746520697320746865204b45592c206e6f7420612076616c7565206669656c64202845444943542d4f505449432d54454d504c4154452d4f574e45522d3030312c0a3b2045444943542d4142492d4f5050524f46494c452d554e495155452d303031292e0a6f7065726174696f6e2d70726f66696c65203d207b0a20206f7074696354656d706c6174653a206f707469632d74656d706c6174652c0a20206566666563745072656469636174653a20747374722c20202020202020202020203b20636f6f7264696e617465206f6620746865206f7065726174696f6e2d6d6f6465207072656469636174650a7d0a0a6f707469632d74656d706c617465203d207b0a20206f707469634b696e643a2022726576656c6174696f6e22202f20226166666563745265696e746567726174696f6e222c0a2020626f756e646172794b696e643a202270726f6a656374696f6e22202f2022616666656374222c0a2020737570706f7274506f6c6963793a20747374722c202020202020202020202020203b2063616e6f6e6963616c20737570706f72742d706f6c69637920636f6f7264696e6174650a20206c6f7373446973706f736974696f6e3a20747374722c20202020202020202020203b2063616e6f6e6963616c206c6f73732d646973706f736974696f6e20636f6f7264696e6174650a20203f20626173697354656d706c6174653a20747374722c20202020202020202020203b206f7074696f6e616c206469676573742d6c6f636b65642062617369732074656d706c61746520636f6f72640a20203b2074686520617065727475726520726571756972656d656e7420746869732074656d706c61746520737570706c6965732e205265717569726564207768656e207468652074656d706c6174650a20203b2069732074686520736f75726365206f66206120436f7265206f707469632773206170657274757265526571756972656d656e742028692e652e2074686520696e74656e7420686173206e6f0a20203b20736f757263652060666f6f747072696e74203c3d202e2e2e60292c2073696e6365206170657274757265526571756972656d656e74206973206d616e6461746f727920696e20436f72650a20203b202845444943542d4f505449432d41504552545552452d5245462d303031292e0a20203f206170657274757265526571756972656d656e743a2061706572747572652d726571756972656d656e742c0a7d0a0a3b206170657274757265526571756972656d656e742069732061207479706564207265666572656e63652c206e65766572206120667265652d666f726d20737472696e672e2041207265766965770a3b2072656e646572696e67206d61792073686f772069747320636f6f7264696e617465202845444943542d4f505449432d41504552545552452d5245462d303031292e0a61706572747572652d726571756972656d656e74203d20666f6f747072696e742d6365696c696e672d726566202f2061627374726163742d666f6f747072696e742d6f626c69676174696f6e2d7265660a666f6f747072696e742d6365696c696e672d726566203d207b206b696e643a2022666f6f747072696e744365696c696e67222c207265663a2074737472207d0a61627374726163742d666f6f747072696e742d6f626c69676174696f6e2d726566203d207b206b696e643a20226162737472616374466f6f747072696e744f626c69676174696f6e222c207265663a2074737472207d0a0a3b202d2d2d2065646963742d636f72652e6364646c202d2d2d0a3b2065646963742d636f72652e6364646c0a3b204e6f726d617469766520736368656d6120666f722074686520456469637420436f72652076312073656d616e746963206d6f64656c2e0a3b0a3b2053636f706520626f756e646172793a20746869732066696c6520646566696e657320436f7265206d65616e696e6720616e6420736368656d61207368617065206f6e6c792e20497420646f65730a3b206e6f7420646566696e6520612063616e6f6e6963616c20656e636f6465722c20436f7265206d6f64756c652068617368206669656c64732c20686173682066697874757265732c207461726765740a3b206c6f776572696e672c2061646d697373696f6e2062756e646c65732c206f72207461726765742d6f776e65642049522e0a0a636f72652d6d6f64756c65203d207b0a202061706956657273696f6e3a202265646963742e636f72652f7631222c0a2020636f6f7264696e6174653a20747374722c0a2020696d706f7274733a205b2a20636f72652d696d706f72745d2c0a202074797065733a207b202a2074737472203d3e20636f72652d74797065207d2c0a2020696e74656e74733a207b202b2074737472203d3e20636f72652d696e74656e74207d2c0a20207265717569726564436f72654361706162696c69746965733a205b2a20747374725d2c0a7d0a0a636f72652d696d706f7274203d207b0a20206b696e643a20226c61777061636b22202f202274617267657422202f2022636f7265222c0a20207265663a207265736f757263652d7265662c0a20203f20616c6961733a20747374722c0a7d0a0a3b202d2d2d207479706573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a636f72652d74797065203d20636f72652d7363616c61722d74797065202f20636f72652d7265636f72642d74797065202f20636f72652d76617269616e742d74797065202f0a202020202020202020202020636f72652d6f7074696f6e2d74797065202f20636f72652d6c6973742d74797065202f20636f72652d6d61702d74797065202f0a202020202020202020202020636f72652d6361706162696c6974792d7265662d747970650a0a636f72652d7363616c61722d74797065203d20636f72652d626f6f6c2d74797065202f20636f72652d696e742d74797065202f20636f72652d737472696e672d74797065202f0a20202020202020202020202020202020202020636f72652d62797465732d74797065202f20636f72652d756e69742d747970650a0a636f72652d626f6f6c2d74797065203d207b206b696e643a2022426f6f6c22207d0a636f72652d756e69742d74797065203d207b206b696e643a2022556e697422207d0a636f72652d696e742d74797065203d207b0a20206b696e643a202249363422202f202255363422202f202249333222202f202255333222202f202249313622202f202255313622202f2022493822202f20225538222c0a7d0a636f72652d737472696e672d74797065203d207b0a20206b696e643a2022537472696e67222c0a20206d61783a2075696e742c0a202063616e6f6e6963616c3a2022756e69636f64652d7363616c61722d6e666322202f20227261772d75746638222c0a7d0a636f72652d62797465732d74797065203d207b0a20206b696e643a20224279746573222c0a20206d61783a2075696e742c0a7d0a636f72652d7265636f72642d74797065203d207b0a20206b696e643a20225265636f7264222c0a20206669656c64733a207b202a2074737472203d3e20636f72652d747970652d726566207d2c0a7d0a636f72652d76617269616e742d74797065203d207b0a20206b696e643a202256617269616e74222c0a202063617365733a207b202b2074737472203d3e2076617269616e742d636173652d626f6479207d2c0a7d0a76617269616e742d636173652d626f6479203d207b0a20203f207061796c6f61643a20636f72652d747970652d7265662c0a7d0a636f72652d6f7074696f6e2d74797065203d207b0a20206b696e643a20224f7074696f6e222c0a20206974656d3a20636f72652d747970652d7265662c0a7d0a636f72652d6c6973742d74797065203d207b0a20206b696e643a20224c697374222c0a20206974656d3a20636f72652d747970652d7265662c0a20206d61783a2075696e742c0a7d0a636f72652d6d61702d74797065203d207b0a20206b696e643a20224d6170222c0a20206b65793a20636f72652d747970652d7265662c0a202076616c75653a20636f72652d747970652d7265662c0a20206d61783a2075696e742c0a7d0a636f72652d6361706162696c6974792d7265662d74797065203d207b0a20206b696e643a20224361706162696c697479526566222c0a20206974656d3a20636f72652d747970652d7265662c0a7d0a0a3b20636f72652d747970652d72656620697320646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d612e0a0a3b202d2d2d207265666572656e63657320616e642076616c756573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a3b204c6f63616c206964656e7469747920697320616c7068612d737461626c652e20606964602069732074686520636f6d70696c65722d6f776e6564206c6f63616c20636f6f7264696e6174653b0a3b2060616c7068614e616d656020697320746865206e6f726d616c697a65642068756d616e2f6465627567206e616d652e20536f757263652062696e646572207370656c6c696e67206973206e6f740a3b206964656e746974792e0a6c6f63616c2d726566203d207b0a202069643a20747374722c0a2020616c7068614e616d653a20747374722c0a2020747970653a20636f72652d747970652d7265662c0a7d0a0a636f72652d76616c7565203d20636f72652d6e756c6c2d76616c7565202f20636f72652d626f6f6c2d76616c7565202f20636f72652d696e742d76616c7565202f0a20202020202020202020202020636f72652d737472696e672d76616c7565202f20636f72652d62797465732d76616c7565202f20636f72652d7265636f72642d76616c7565202f0a20202020202020202020202020636f72652d76617269616e742d76616c7565202f20636f72652d6c6973742d76616c7565202f20636f72652d6d61702d76616c7565202f0a20202020202020202020202020636f72652d6361706162696c6974792d76616c75650a0a636f72652d6e756c6c2d76616c7565203d207b206b696e643a20226e756c6c22207d0a636f72652d626f6f6c2d76616c7565203d207b206b696e643a2022626f6f6c222c2076616c75653a20626f6f6c207d0a636f72652d696e742d76616c7565203d207b206b696e643a2022696e74222c2077696474683a20747374722c2076616c75653a20696e74207d0a636f72652d737472696e672d76616c7565203d207b206b696e643a2022737472696e67222c2076616c75653a2074737472207d0a636f72652d62797465732d76616c7565203d207b206b696e643a20226279746573222c2076616c75653a2062737472207d0a636f72652d7265636f72642d76616c7565203d207b206b696e643a20227265636f7264222c206669656c64733a207b202a2074737472203d3e20636f72652d76616c7565207d207d0a636f72652d76617269616e742d76616c7565203d207b0a20206b696e643a202276617269616e74222c0a2020747970653a20636f72652d747970652d7265662c0a2020636173653a20747374722c0a20203f207061796c6f61643a20636f72652d76616c75652c0a7d0a636f72652d6c6973742d76616c7565203d207b206b696e643a20226c697374222c2076616c7565733a205b2a20636f72652d76616c75655d207d0a636f72652d6d61702d76616c7565203d207b206b696e643a20226d6170222c20656e74726965733a205b2a205b6b65793a20636f72652d76616c75652c2076616c75653a20636f72652d76616c75655d5d207d0a636f72652d6361706162696c6974792d76616c7565203d207b0a20206b696e643a20226361706162696c697479222c0a2020726563656970743a207368613235362d6469676573742c0a7d0a0a3b2045646963742d617574686f72656420707572652068656c70657273207573652061207075726520436f72652066756e6374696f6e20626f64792e2054686520626f64792063616e2062696e640a3b20707572652065787072657373696f6e7320616e642072657475726e20616e2065787072657373696f6e2c206275742069742063616e6e6f7420636f6e7461696e20436f7265206566666563742c0a3b2067756172642c206272616e63682c206c6f6f702c206d617463682d6e6f64652c206f722070726f6f662d6f626c69676174696f6e206e6f6465732e0a636f72652d666e2d626f6479203d207b0a2020706172616d733a205b2a206c6f63616c2d7265665d2c0a2020626f64793a20636f72652d707572652d626c6f636b2c0a7d0a0a636f72652d707572652d626c6f636b203d207b0a20206c6f63616c733a205b2a206c6f63616c2d7265665d2c0a202062696e64696e67733a205b2a20707572652d6c65742d6e6f64655d2c0a2020726573756c743a20636f72652d657870722c0a7d0a0a707572652d6c65742d6e6f6465203d207b0a20206b696e643a20226c6574222c0a202062696e64696e673a206c6f63616c2d7265662c0a202076616c75653a20636f72652d657870722c0a7d0a0a3b202d2d2d2065787072657373696f6e7320616e642070726564696361746573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a636f72652d65787072203d206c6f63616c2d65787072202f20636f6e73742d65787072202f207265636f72642d65787072202f206669656c642d65787072202f0a20202020202020202020202076617269616e742d65787072202f206d617463682d65787072202f2063616c6c2d65787072202f206c6973742d65787072202f206d61702d65787072202f0a20202020202020202020202069662d657870720a0a6c6f63616c2d65787072203d207b206b696e643a20226c6f63616c222c207265663a206c6f63616c2d726566207d0a636f6e73742d65787072203d207b206b696e643a2022636f6e7374222c2076616c75653a20636f72652d76616c7565207d0a7265636f72642d65787072203d207b206b696e643a20227265636f7264222c206669656c64733a207b202a2074737472203d3e20636f72652d65787072207d207d0a6669656c642d65787072203d207b206b696e643a20226669656c64222c20626173653a20636f72652d657870722c206669656c643a2074737472207d0a76617269616e742d65787072203d207b0a20206b696e643a202276617269616e74222c0a2020747970653a20636f72652d747970652d7265662c0a2020636173653a20747374722c0a20203f207061796c6f61643a20636f72652d657870722c0a7d0a6d617463682d65787072203d207b0a20206b696e643a20226d61746368222c0a20207363727574696e65653a20636f72652d657870722c0a202061726d733a205b2b206d617463682d61726d5d2c0a7d0a6d617463682d61726d203d207b0a2020636173653a20747374722c0a20203f2062696e6465723a206c6f63616c2d7265662c0a2020626f64793a20636f72652d657870722c0a7d0a63616c6c2d65787072203d207b0a20206b696e643a202263616c6c222c0a202063616c6c65653a20747374722c0a202074797065417267733a205b2a20636f72652d747970652d7265665d2c0a2020617267733a205b2a20636f72652d657870725d2c0a7d0a6c6973742d65787072203d207b206b696e643a20226c697374222c2076616c7565733a205b2a20636f72652d657870725d207d0a6d61702d65787072203d207b206b696e643a20226d6170222c20656e74726965733a205b2a205b6b65793a20636f72652d657870722c2076616c75653a20636f72652d657870725d5d207d0a69662d65787072203d207b0a20206b696e643a20226966222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20207468656e3a20636f72652d657870722c0a2020656c73653a20636f72652d657870722c0a7d0a0a636f72652d707265646963617465203d20747275652d707265646963617465202f2066616c73652d707265646963617465202f206e6f742d707265646963617465202f0a2020202020202020202020202020202020616c6c2d707265646963617465202f20616e792d707265646963617465202f20636f6d706172652d707265646963617465202f0a202020202020202020202020202020202063616c6c2d707265646963617465202f206f62737472756374696f6e2d7072656469636174650a0a747275652d707265646963617465203d207b206b696e643a20227472756522207d0a66616c73652d707265646963617465203d207b206b696e643a202266616c736522207d0a6e6f742d707265646963617465203d207b206b696e643a20226e6f74222c2076616c75653a20636f72652d707265646963617465207d0a616c6c2d707265646963617465203d207b206b696e643a2022616c6c222c2076616c7565733a205b2b20636f72652d7072656469636174655d207d0a616e792d707265646963617465203d207b206b696e643a2022616e79222c2076616c7565733a205b2b20636f72652d7072656469636174655d207d0a636f6d706172652d707265646963617465203d207b0a20206b696e643a2022636f6d70617265222c0a20206f703a20223d3d22202f2022213d22202f20223c22202f20223c3d22202f20223e22202f20223e3d222c0a20206c6566743a20636f72652d657870722c0a202072696768743a20636f72652d657870722c0a7d0a63616c6c2d707265646963617465203d207b0a20206b696e643a202263616c6c222c0a20207072656469636174653a20747374722c0a2020617267733a205b2a20636f72652d657870725d2c0a7d0a6f62737472756374696f6e2d707265646963617465203d207b0a20206b696e643a20226f62737472756374696f6e222c0a2020636f6f7264696e6174653a206661696c7572652d6964656e742c0a20207061796c6f61643a20636f72652d657870722c0a7d0a0a696e7075742d636f6e73747261696e74203d207b0a2020636f6f7264696e6174653a20747374722c0a2020736f757263653a2022776865726522202f2022636f6d70696c6572222c0a20207072656469636174653a20636f72652d7072656469636174652c0a7d0a0a3b202d2d2d20696e74656e74732c20626c6f636b732c20616e64206e6f646573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a636f72652d696e74656e74203d207b0a2020696e7075743a20636f72652d747970652d7265662c0a20206f75747075743a20636f72652d747970652d7265662c0a202072657175697265644f7065726174696f6e50726f66696c653a20747374722c0a20203f2062617369733a20636f72652d657870722c0a2020696e707574436f6e73747261696e74733a205b2a20696e7075742d636f6e73747261696e745d2c0a2020636f72654576616c756174696f6e4275646765743a20636f72652d6275646765742c0a2020626f64793a20636f72652d626c6f636b2c0a20203f206f707469633a20636f72652d6f707469632c0a7d0a0a636f72652d627564676574203d207b0a20206d617853746570733a2075696e742c0a20206d6178416c6c6f636174656442797465733a2075696e742c0a20206d61784f757470757442797465733a2075696e742c0a7d0a0a636f72652d6f70746963203d207b0a20206f707469634b696e643a2022726576656c6174696f6e22202f20226166666563745265696e746567726174696f6e222c0a2020626f756e646172794b696e643a202270726f6a656374696f6e22202f2022616666656374222c0a20206170657274757265526571756972656d656e743a2061706572747572652d726571756972656d656e742c0a2020737570706f7274506f6c6963793a20747374722c0a20206c6f7373446973706f736974696f6e3a20747374722c0a7d0a0a636f72652d626c6f636b203d207b0a20206c6f63616c733a205b2a206c6f63616c2d7265665d2c0a20206e6f6465733a205b2a20636f72652d6e6f64655d2c0a2020726573756c743a20636f72652d657870722c0a7d0a0a636f72652d6e6f6465203d206c65742d6e6f6465202f20726571756972652d6e6f6465202f206566666563742d6e6f6465202f2067756172642d6e6f6465202f206272616e63682d6e6f6465202f0a202020202020202020202020666f722d6e6f6465202f206d617463682d6e6f6465202f2070726f6f662d6f626c69676174696f6e2d6e6f64650a0a6c65742d6e6f6465203d207b0a20206b696e643a20226c6574222c0a202062696e64696e673a206c6f63616c2d7265662c0a202076616c75653a20636f72652d657870722c0a7d0a726571756972652d6e6f6465203d207b0a20206b696e643a202272657175697265222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20206f6e4661696c7572653a20726571756972652d6661696c7572652d61726d2c0a7d0a726571756972652d6661696c7572652d61726d203d207465726d696e616c2d726571756972652d6661696c757265202f0a20202020202020202020202020202020202020202020636f6e74696e75652d6f6273747275637465642d726571756972652d6661696c7572650a7465726d696e616c2d726571756972652d6661696c757265203d207b0a20206b696e643a20227465726d696e616c222c0a2020726561736f6e3a206f62737472756374696f6e2d726561736f6e2c0a7d0a636f6e74696e75652d6f6273747275637465642d726571756972652d6661696c757265203d207b0a20206b696e643a2022636f6e74696e75654f627374727563746564222c0a2020726561736f6e3a206f62737472756374696f6e2d726561736f6e2c0a7d0a6f62737472756374696f6e2d726561736f6e203d207b0a2020726561736f6e4b696e643a20747374722c0a20207061796c6f61643a207b202a2074737472203d3e20636f72652d65787072207d2c0a7d0a6566666563742d6e6f6465203d207b0a20206b696e643a2022656666656374222c0a202062696e64696e673a206c6f63616c2d7265662c0a20206566666563743a20747374722c0a2020696e7075743a20636f72652d657870722c0a20206f62737472756374696f6e4d61703a207b202a206661696c7572652d6964656e74203d3e206f62737472756374696f6e2d61726d207d2c0a7d0a6f62737472756374696f6e2d61726d203d207b0a202062696e6465723a206c6f63616c2d7265662c0a202076616c75653a20636f72652d657870722c0a7d0a67756172642d6e6f6465203d207b0a20206b696e643a20226775617264222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20206f62737472756374696f6e3a20636f72652d657870722c0a7d0a6272616e63682d6e6f6465203d207b0a20206b696e643a20226272616e6368222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20207468656e3a20636f72652d626c6f636b2c0a2020656c73653a20636f72652d626c6f636b2c0a7d0a666f722d6e6f6465203d207b0a20206b696e643a2022666f72222c0a202062696e6465723a206c6f63616c2d7265662c0a2020697465723a20636f72652d657870722c0a2020626f756e643a20636f72652d626f756e642c0a2020626f64793a20636f72652d626c6f636b2c0a7d0a6d617463682d6e6f6465203d207b0a20206b696e643a20226d61746368222c0a20207363727574696e65653a20636f72652d657870722c0a202061726d733a205b2b206d617463682d626c6f636b2d61726d5d2c0a7d0a6d617463682d626c6f636b2d61726d203d207b0a2020636173653a20747374722c0a20203f2062696e6465723a206c6f63616c2d7265662c0a2020626f64793a20636f72652d626c6f636b2c0a7d0a70726f6f662d6f626c69676174696f6e2d6e6f6465203d207b0a20206b696e643a202270726f6f66222c0a2020636f6f7264696e6174653a20747374722c0a20207072656469636174653a20636f72652d7072656469636174652c0a7d0a0a636f72652d626f756e64203d206c69746572616c2d626f756e64202f20636f6f7264696e6174652d626f756e640a6c69746572616c2d626f756e64203d207b206b696e643a20226c69746572616c222c2076616c75653a2075696e74207d0a636f6f7264696e6174652d626f756e64203d207b206b696e643a2022636f6f7264696e617465222c207265663a2074737472207d0a0a3b20536861726564207265736f757263652d7265662c207368613235362d6469676573742c206661696c7572652d6964656e742c2061706572747572652d726571756972656d656e742c20616e640a3b20636f72652d747970652d7265662061726520646566696e6564206f6e636520696e2065646963742d636f6d6d6f6e2e6364646c2e0a0a3b202d2d2d2065646963742d6c61777061636b2e6364646c202d2d2d0a3b2065646963742d6c61777061636b2e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f7220746865204564696374206c61777061636b206d616e696665737420616e64206578706f727420737572666163652e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e204a534f4e20696e207468652070726f73652073706563730a3b2069732061207265766965772072656e646572696e672067656e6572617465642066726f6d207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a6c61777061636b2d6d616e6966657374203d207b0a202061706956657273696f6e3a202265646963742e6c61777061636b2f7631222c0a202069643a20747374722c0a202076657273696f6e3a20747374722c0a20206163636570746564436f72654162693a205b2b20747374725d2c0a2020646570656e64656e636965733a205b2a206c61777061636b2d6465705d2c202020202020202020203b20616379636c69632c206469676573742d6c6f636b6564202845444943542d4c41575041434b2d4441472d303031290a20206578706f7274733a207265736f757263652d7265662c0a20203f2074617267657441646170746572733a205b2b207461726765742d616461707465725d2c2020203b207265717569726564206f6e6c7920696620616e792072756e74696d6520656666656374206578697374730a20203f2068656c706572436f6d706f6e656e743a2065786563757461626c652d636f6d706f6e656e742c203b2065786563757461626c652068656c70657273206361727279207468656972206f776e2073616e64626f782b6675656c0a202076657269666965723a2076657269666965722c202020202020202020202020202020202020202020203b20636c61737369666965643a206465636c61726174697665206f722065786563757461626c650a2020636f6d7061746962696c6974793a207265736f757263652d7265662c0a2020636f6e666f726d616e636546697874757265436f727075733a207265736f757263652d7265662c0a7d0a0a3b2041207665726966696572206973206569746865722061206465636c617261746976652072756c6573657420286e6f2072756e74696d6529206f7220616e2065786563757461626c650a3b20636f6d706f6e656e742e20416e2065786563757461626c65207665726966696572204d55535420636172727920697473206f776e2073616e64626f7820616e64206675656c206d6f64656c2c0a3b20736f2074686520736368656d6120656e666f726365732074686174206e6f2065786563757461626c6520636f6d706f6e656e74206973206c65667420756e626f756e6465640a3b202845444943542d4142492d56455249464945522d424f554e442d303031292e0a7665726966696572203d206465636c617261746976652d7665726966696572202f2065786563757461626c652d76657269666965720a6465636c617261746976652d7665726966696572203d207b20636c6173733a20226465636c61726174697665222c2072756c657365743a207265736f757263652d726566207d0a65786563757461626c652d7665726966696572203d207b0a2020636c6173733a202265786563757461626c65222c0a2020636f6d706f6e656e743a207265736f757263652d7265662c0a202073616e64626f783a207265736f757263652d7265662c0a20206675656c4d6f64656c3a207265736f757263652d7265662c0a7d0a0a3b20416e792065786563757461626c6520636f6d706f6e656e7420697320626f756e64656420627920697473206f776e2073616e64626f78202b206675656c206d6f64656c2e0a65786563757461626c652d636f6d706f6e656e74203d207b0a2020636f6d706f6e656e743a207265736f757263652d7265662c0a202073616e64626f783a207265736f757263652d7265662c0a20206675656c4d6f64656c3a207265736f757263652d7265662c0a7d0a0a6c61777061636b2d646570203d207b2069643a20747374722c2076657273696f6e3a20747374722c206469676573743a207368613235362d646967657374207d0a0a3b20416461707465722073656c656374696f6e206b65797320534f4c454c59206f666620746865206469676573742d6c6f636b65642060616363657074656454617267657450726f66696c65600a3b20286974732060696460206973207468652070726f66696c652069643b206974732060646967657374602070696e73207468652065786163742070726f66696c652f76657273696f6e292e2054686572650a3b20617265206e6f20696e646570656e64656e7420646973706c617920737472696e6773207468617420636f756c64206469736167726565207769746820746865206c6f636b2c20736f20610a3b207265736f6c7665722063616e6e6f742062696e6420616e206164617074657220746f206f6e6520746172676574207768696c6520746865206c6f636b2070726f76657320616e6f746865720a3b202845444943542d4c41575041434b2d414441505445522d54415247455449522d303031292e0a7461726765742d61646170746572203d207b0a2020616363657074656454617267657450726f66696c653a207265736f757263652d7265662c202020203b206469676573742d6c6f636b65642c20617574686f72697461746976652073656c6563746f720a2020616363657074656454617267657449723a207265736f757263652d7265662c2020202020202020203b206469676573742d6c6f636b65640a2020616461707465723a207265736f757263652d7265662c0a7d0a0a3b20536861726564207479706573207265736f757263652d72656620616e64207368613235362d6469676573742061726520646566696e6564206f6e636520696e0a3b2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a3b202d2d2d206578706f72742073757266616365202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a6c61777061636b2d6578706f727473203d207b0a202074797065733a205b2a206578706f727465642d747970655d2c0a2020636f6e7374616e74733a205b2a206578706f727465642d636f6e7374616e745d2c0a20207075726546756e6374696f6e733a205b2a20707572652d66756e6374696f6e5d2c0a2020656666656374733a205b2a2073656d616e7469632d6566666563745d2c0a20206f62737472756374696f6e733a205b2a206f62737472756374696f6e2d6465665d2c0a20203b206b65796564206279206f7065726174696f6e2d70726f66696c6520636f6f7264696e61746520e2869220756e697175656e65737320656e666f726365640a20203b202845444943542d4142492d4f5050524f46494c452d554e495155452d303031290a20203b206f7065726174696f6e2d70726f66696c65207265636f7264732074686973206c61777061636b206578706f72747320286f707469632074656d706c6174657320746861740a20203b2060696d706c656d656e7473602f6070726f66696c656020636c6175736573207265736f6c766520616761696e7374292e206f7065726174696f6e2d70726f66696c652069730a20203b20646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c202845444943542d4142492d4f5050524f46494c452d534c4f542d303031292e0a20206f7065726174696f6e50726f66696c65733a207b202a2074737472203d3e206f7065726174696f6e2d70726f66696c65207d2c20203b206b6579656420627920636f6f7264696e6174650a7d0a0a6578706f727465642d7479706520202020203d207b20636f6f7264696e6174653a20747374722c20646566696e6974696f6e3a20636f72652d747970652d726566207d0a6578706f727465642d636f6e7374616e74203d207b20636f6f7264696e6174653a20747374722c20747970653a20636f72652d747970652d7265662c2076616c75653a20616e79207d0a0a3b204120707572652068656c7065722069732061206469736372696d696e6174656420756e696f6e2062792060736f75726365602c20736f2074686520736368656d6120697473656c660a3b2067756172616e7465657320616e20696d706c656d656e746174696f6e20657869737473202845444943542d4c41575041434b2d505552452d494d504c2d303031293a0a3b2020202d20226564696374223a20617574686f72656420696e2045646963742f436f72653b2074686520436f726520626f6479206973206361727269656420696e6c696e6520286861736865640a3b20202020207769746820746865206578706f72742073757266616365292e2054686520736368656d61207265717569726573207468652060626f647960206669656c642e0a3b2020202d2022636f6d706f6e656e74223a20696d706c656d656e746564206f7574736964652045646963743b2063617272696573206e6f20696e6c696e6520626f647920616e6420696e73746561640a3b20202020206361727269657320697473206f776e206469676573742d6c6f636b65642060696d706c656d656e746174696f6e60202873616e64626f78202b206675656c292e20497420646f65730a3b20202020206e6f7420646570656e64206f6e20746865206f7074696f6e616c206d616e69666573742d6c6576656c2068656c706572436f6d706f6e656e742e0a707572652d66756e6374696f6e203d2065646963742d707572652d66756e6374696f6e202f20636f6d706f6e656e742d707572652d66756e6374696f6e0a0a707572652d66756e6374696f6e2d636f6d6d6f6e203d20280a2020636f6f7264696e6174653a20747374722c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020706172616d6574657254797065733a205b2a20636f72652d747970652d7265665d2c2020202020203b20616c6c20626f756e6465640a202072657475726e547970653a20636f72652d747970652d7265662c20202020202020202020202020203b20626f756e6465640a2020636f737454656d706c6174653a20747374722c0a202064657465726d696e69736d436c6173733a2022746f74616c22202f2022746f74616c2d776974682d74797065642d646961676e6f73746963222c0a290a0a65646963742d707572652d66756e6374696f6e203d207b0a2020707572652d66756e6374696f6e2d636f6d6d6f6e2c0a2020736f757263653a20226564696374222c0a2020626f64793a20636f72652d666e2d626f64792c2020202020202020202020202020202020202020203b20696e6c696e652c20686173682d7369676e69666963616e740a7d0a0a636f6d706f6e656e742d707572652d66756e6374696f6e203d207b0a2020707572652d66756e6374696f6e2d636f6d6d6f6e2c0a2020736f757263653a2022636f6d706f6e656e74222c0a20203b20746865206469676573742d6c6f636b656420636f6d706f6e656e7420696d706c656d656e74696e6720746869732068656c7065722e2052657175697265642061742074686520736368656d610a20203b206c6576656c20736f206120636f6d706f6e656e742068656c7065722063616e206e657665722076616c696461746520776974686f7574206120686173682d626f756e642c0a20203b2073616e64626f782b6675656c2d64657363726962656420696d706c656d656e746174696f6e202845444943542d4c41575041434b2d505552452d494d504c2d303031292e0a2020696d706c656d656e746174696f6e3a2065786563757461626c652d636f6d706f6e656e742c0a7d0a0a3b20636f72652d666e2d626f647920697320646566696e65642062792065646963742d636f72652e6364646c20616e6420617373656d626c656420776974682074686973206c61777061636b0a3b20736368656d612e2049742069732061207075726520436f72652066756e6374696f6e20626f64792c206e6f7420616e206566666563742d63617061626c6520636f72652d626c6f636b2e0a0a73656d616e7469632d656666656374203d207b0a2020636f6f7264696e6174653a20747374722c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020696e707574547970653a20636f72652d747970652d7265662c2020202020202020202020202020203b20626f756e6465640a20206f7574707574547970653a20636f72652d747970652d7265662c20202020202020202020202020203b20626f756e6465640a2020657865637574696f6e436c6173733a202270726f6f664f6e6c7922202f202272756e74696d65222c2020203b206f7274686f676f6e616c20746f207772697465436c6173730a20206566666563744b696e6448696e743a206566666563742d6b696e642c0a2020666f6f747072696e744f626c69676174696f6e3a20747374722c0a2020636f73744f626c69676174696f6e3a20747374722c0a20206566666563744661696c757265733a207b202a206661696c7572652d6964656e74203d3e206566666563742d6661696c7572652d626f6479207d2c20203b206b6579656420627920636f6f7264696e6174653b20756e697175650a20206775617264537570706f72743a20626f6f6c2c0a7d0a0a6f62737472756374696f6e2d646566203d207b0a2020636f6f7264696e6174653a20747374722c0a2020617574686f72697479436c6173733a20617574686f726974792d636c6173732c0a20207061796c6f6164536368656d613a20636f72652d747970652d7265662c20202020202020202020203b2074797065642c20626f756e64656420286d617920626520656d707479207265636f7264290a7d0a0a3b206566666563742d6661696c7572652d626f64792c206566666563742d6b696e642c20617574686f726974792d636c6173732c20616e6420636f72652d747970652d7265662061726520646566696e65640a3b206f6e636520696e2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a3b202d2d2d2065646963742d6c61777061636b2d616461707465722e6364646c202d2d2d0a3b2065646963742d6c61777061636b2d616461707465722e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f72206f6e6520646972656374206465636c61726174697665206c61777061636b2074617267657420616461707465722e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a3b0a3b2054686520656e636c6f73696e67206c61777061636b206d616e69666573742073656c6563747320746865206578616374207461726765742070726f66696c652c207461726765742049522c0a3b20616e642061646170746572207265736f75726365206469676573742e2054686f7365206964656e74697469657320617265206e6f7420726570656174656420686572652e0a0a6c61777061636b2d61646170746572203d207b0a202061706956657273696f6e3a202265646963742e6c61777061636b2d616461707465722f7631222c0a2020636c6173733a20226465636c61726174697665222c0a20206f7065726174696f6e50726f66696c65733a207b0a202020202a2074737472203d3e206c61777061636b2d616461707465722d6f7065726174696f6e2d70726f66696c650a20207d2c0a2020656666656374496d706c656d656e746174696f6e733a207b0a202020202a2074737472203d3e206c61777061636b2d616461707465722d6566666563740a20207d2c0a2020627564676574733a207b0a202020202a2074737472203d3e206c61777061636b2d616461707465722d6275646765740a20207d2c0a7d0a0a3b204b657973206172652063616e6f6e6963616c206c61777061636b206f7065726174696f6e2d70726f66696c6520636f6f7264696e617465732e0a6c61777061636b2d616461707465722d6f7065726174696f6e2d70726f66696c65203d207b0a2020636f72653a20747374722c0a202073656d616e746963456666656374733a205b2b20747374725d2c0a7d0a0a3b204b657973206172652063616e6f6e6963616c206c61777061636b2073656d616e7469632d65666665637420636f6f7264696e617465732e20466f6f747072696e742c20636f73742c20616e640a3b206661696c757265206669656c6473206d7573742065786163746c792064697363686172676520746865206d61746368696e67206578706f72746564206566666563742e0a6c61777061636b2d616461707465722d656666656374203d207b0a2020746172676574496e7472696e7369633a20747374722c0a2020746172676574436f6e66696775726174696f6e3a207265736f757263652d7265662c0a20207772697465436c6173733a206c61777061636b2d616461707465722d77726974652d636c6173732c0a2020666f6f747072696e744f626c69676174696f6e3a20747374722c0a2020636f73744f626c69676174696f6e3a20747374722c0a20206661696c7572654d617070696e67733a207b202a206661696c7572652d6964656e74203d3e2074737472207d2c0a7d0a0a3b204b657973206172652063616e6f6e6963616c206578706f7274656420636f73742d6f626c69676174696f6e20636f6f7264696e617465732e0a6c61777061636b2d616461707465722d627564676574203d207b0a20206d617853746570733a2075696e742c0a20206d6178416c6c6f636174656442797465733a2075696e742c0a20206d61784f757470757442797465733a2075696e742c0a7d0a0a6c61777061636b2d616461707465722d77726974652d636c617373203d20226e6f6e6522202f20227265616422202f202263726561746522202f2022656e7375726522202f0a20202020202020202020202020202020202020202020202020202020202022617070656e6422202f20227265706c61636522202f202264656c65746522202f2022637573746f6d220a0a3b206661696c7572652d6964656e7420697320646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c2e0a0a3b202d2d2d2065646963742d7461726765742d70726f66696c652e6364646c202d2d2d0a3b2065646963742d7461726765742d70726f66696c652e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f7220746865204564696374207461726765742070726f66696c65206d616e69666573742e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76310a3b202873656520535045435f636f6e74696e75756d2d636f6e74726163742d62756e646c652d76312e6d64292e204a534f4e20696e207468652070726f736520737065637320697320610a3b207265766965772072656e646572696e672067656e6572617465642066726f6d207468697320736368656d613b2074686973204344444c206973207468652073696e676c6520736f757263650a3b206f66207472757468202845444943542d4142492d4e4f4455502d303031292e0a0a7461726765742d70726f66696c652d6d616e6966657374203d207b0a202061706956657273696f6e3a202265646963742e7461726765742d70726f66696c652f7631222c0a202069643a20747374722c202020202020202020202020202020202020202020202020203b20652e672e20226563686f2e64706f220a202076657273696f6e3a20747374722c20202020202020202020202020202020202020203b20652e672e202231220a20206163636570746564436f72654162693a205b2b20747374725d2c20202020202020203b20652e672e205b2265646963742e636f72652f7631225d0a0a2020696e7472696e736963733a207265736f757263652d7265662c0a2020696e7472696e7369634e616d6573706163653a20747374722c0a20203b207075626c697368657320746869732070726f66696c652773206f7065726174696f6e2d70726f66696c65207265636f72647320286f707469632074656d706c6174657320746861740a20203b206070726f66696c65602f60696d706c656d656e74736020636c6175736573207265736f6c766520616761696e7374292e205265666572656e63657320616e0a20203b206f7065726174696f6e2d70726f66696c65732d646f63756d656e74202845444943542d4142492d4f5050524f46494c452d534c4f542d303031292e0a20206f7065726174696f6e50726f66696c65733a207265736f757263652d7265662c0a2020666f6f747072696e74416c67656272613a207265736f757263652d7265662c0a2020636f7374416c67656272613a207265736f757263652d7265662c0a202074617267657449723a207265736f757263652d7265662c0a20206f62737472756374696f6e5461786f6e6f6d793a207265736f757263652d7265662c0a202076657269666965723a207265736f757263652d7265662c0a20206c6f77657265723a207265736f757263652d7265662c0a202073616e64626f783a207265736f757263652d7265662c0a20206675656c4d6f64656c3a207265736f757263652d7265662c0a0a20203b206669656c647320746865206c616e67756167652073706563207265717569726573206f662065766572792070726f66696c650a202062756e646c6550726f66696c653a207265736f757263652d7265662c0a202067656e657261746564417274696661637450726f66696c65733a205b2a207265736f757263652d7265665d2c0a202063616e6f6e6963616c456e636f64696e6752756c65733a207265736f757263652d7265662c0a20203b20412070726f66696c65207468617420616363657074732074686520646972656374206465636c61726174697665206c61777061636b2d6164617074657220414249206e616d65732069740a20203b2065786163746c79206f6e63652e2050726f66696c6573207468617420646f206e6f7420636f6e73756d65206c61777061636b206164617074657273206c6561766520746869730a20203b206f7074696f6e616c20736c6f7420616273656e74206f7220656d7074792e0a20203f2061636365707465644c61777061636b416461707465724162693a205b5d202f205b2265646963742e6c61777061636b2d616461707465722f7631225d2c0a2020646961676e6f737469634162693a207265736f757263652d7265662c0a0a20203b206170706c69636174696f6e20646f637472696e650a20206170706c69636174696f6e4d6f64656c3a202261746f6d6963222c0a202072656164436f6e73697374656e63793a20226170706c69636174696f6e2d736e617073686f7422202f20747374722c0a202067756172644576616c756174696f6e3a2022707265636f6d6d69742d61746f6d696322202f20747374722c0a20206f62737472756374696f6e526f6c6c6261636b3a20226e6f2d76697369626c652d6566666563747322202f20747374722c0a20206d756c74695461726765743a20626f6f6c2c0a20203b207768657468657220746865207461726765742063616e206576616c7561746520707265636f6d6d697420706f7374636f6e646974696f6e20286067756172616e746565602920636865636b730a20203b20696e73696465207468652061746f6d6963206170706c69636174696f6e20756e6974202845444943542d5441524745542d504f5354434f4e442d303031290a2020706f7374636f6e646974696f6e537570706f72743a20626f6f6c2c0a0a202064657465726d696e6973746963457865637574696f6e3a207265736f757263652d7265662c0a2020636f6e666f726d616e636546697874757265436f727075733a207265736f757263652d7265662c0a7d0a0a3b20536861726564207479706573207265736f757263652d72656620616e64207368613235362d6469676573742061726520646566696e6564206f6e636520696e0a3b2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d6120627920746865206275696c640a3b202845444943542d4142492d4e4f4455502d303031292e205468657920617265206e6f74207265646566696e656420686572652e0a0a3b202d2d2d20696e7472696e736963207369676e6174757265202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a3b20546865206172746966616374207265666572656e63656420627920746865206d616e696665737427732060696e7472696e7369637360207265736f757263652d726566206973207468650a3b20696e7472696e7369632d7369676e617475726520636f7270757320646f63756d656e742062656c6f772e20497473206c61796f757420697320666978656420736f2074776f0a3b20696e646570656e64656e742070726f66696c65732076616c69646174652f686173682074686520636f72707573206964656e746963616c6c790a3b202845444943542d4142492d494e5452494e534943532d444f432d303031292e0a0a3b20696e7472696e736963732069732061204d4150206b6579656420627920636f6f7264696e6174652c20736f2074686520736368656d6120697473656c6620656e666f726365730a3b20636f6f7264696e61746520756e697175656e6573732e20412070726f766964657220726563656976657320746865207265736f6c76656420636f7270757320617320610a3b206469676573742d626f756e642073656d616e74696320696e70757420616e64207265736f6c76657320636f6f7264696e617465732077697468696e20746861742061727469666163742e0a3b2045616368206d6170206b6579204d55535420657175616c20697473207265636f726427732060636f6f7264696e61746560206669656c640a3b202845444943542d4142492d494e5452494e5349432d554e495155452d303031292e0a696e7472696e736963732d646f63756d656e74203d207b0a202061706956657273696f6e3a202265646963742e7461726765742d70726f66696c652e696e7472696e736963732f7631222c0a2020696e7472696e736963733a207b202a2074737472203d3e20696e7472696e736963207d2c0a7d0a0a3b20546865206172746966616374207265666572656e63656420627920746865206d616e6966657374277320606f7065726174696f6e50726f66696c657360207265736f757263652d7265662e0a3b206f7065726174696f6e2d70726f66696c65202f206f707469632d74656d706c6174652061726520646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c2e204b657965642062790a3b20636f6f7264696e61746520736f207265736f6c7574696f6e2063616e2774207069636b206265747765656e2074776f2073616d652d636f6f7264696e6174652070726f66696c65730a3b202845444943542d4142492d4f5050524f46494c452d534c4f542d3030312c2045444943542d4142492d4f5050524f46494c452d554e495155452d303031292e0a6f7065726174696f6e2d70726f66696c65732d646f63756d656e74203d207b0a202061706956657273696f6e3a202265646963742e7461726765742d70726f66696c652e6f7065726174696f6e2d70726f66696c65732f7631222c0a202070726f66696c65733a207b202a2074737472203d3e206f7065726174696f6e2d70726f66696c65207d2c0a7d0a0a3b2041207479706564207072652d6c6f776572696e67207175657374696f6e20746861742063616e2062652070726f706f73656420627920576174736f6e206f7220616e206167656e7420616e640a3b20636865636b65642062792074686520636f6d70696c65722e2049742069732063616e6f6e6963616c2d43424f5220656e636f64656420756e6465720a3b206065646963742e6c6f776572696e672d726571756972656d656e74732f7631603b2074686520636f6d70696c657220636865636b7320746869732061727469666163742c206e6f74207468650a3b2070726f736520746861742070726f64756365642069742e0a6c6f776572696e672d726571756972656d656e7473203d207b0a202061706956657273696f6e3a202265646963742e6c6f776572696e672d726571756972656d656e74732f7631222c0a20206f7065726174696f6e50726f66696c653a20747374722c0a202073656d616e746963456666656374733a205b2a2073656d616e7469632d6566666563742d726571756972656d656e745d2c0a202072657175697265645772697465436c61737365733a205b2a2077726974652d636c6173735d2c0a202067756172644b696e64733a205b2a2067756172642d6b696e645d2c0a202061746f6d69636974793a2061746f6d69636974792d726571756972656d656e742c0a2020706f7374636f6e646974696f6e537570706f72743a20626f6f6c2c0a20206f62737472756374696f6e436f6f7264696e617465733a205b2a20747374725d2c0a2020666f6f747072696e744f626c69676174696f6e733a205b2a20747374725d2c0a2020636f73744f626c69676174696f6e733a205b2a20747374725d2c0a20206f70746963436f6e74726163743a20747374722c0a7d0a0a73656d616e7469632d6566666563742d726571756972656d656e74203d207b0a2020636f6f7264696e6174653a20747374722c0a20207772697465436c6173733a2077726974652d636c6173732c0a202067756172644b696e64733a205b2a2067756172642d6b696e645d2c0a20206f62737472756374696f6e436f6f7264696e617465733a205b2a20747374725d2c0a2020666f6f747072696e744f626c69676174696f6e733a205b2a20747374725d2c0a2020636f73744f626c69676174696f6e733a205b2a20747374725d2c0a7d0a0a77726974652d636c617373203d20226e6f6e6522202f20227265616422202f202263726561746522202f2022656e7375726522202f2022617070656e6422202f0a2020202020202020202020202020227265706c61636522202f202264656c65746522202f20747374720a67756172642d6b696e64203d2022707265636f6d6d69742d61746f6d696322202f20747374720a61746f6d69636974792d726571756972656d656e74203d202261746f6d696322202f20747374720a0a3b20412067656e75696e6520756e696f6e3a207075726520636f6e7374727563746f7273206361727279206e6f20656666656374206b696e64206f72206661696c757265733b206566666563740a3b20696e7472696e73696373206d757374202845444943542d5441524745542d494e5452494e5349432d434c4153532d303031292e2054686520736368656d6120656e666f7263657320746869732c0a3b206e6f74206120636f6d6d656e742e0a0a3b2054686520696e7472696e736963277320636f6f7264696e6174652069732074686520696e7472696e73696373206d6170204b45592c206e6f7420612076616c7565206669656c642c20736f207468650a3b206b657920616e6420636f6f7264696e6174652063616e206e65766572206469736167726565202845444943542d4142492d494e5452494e5349432d554e495155452d303031292e0a696e7472696e736963203d20707572652d696e7472696e736963202f206566666563742d696e7472696e7369630a0a707572652d696e7472696e736963203d207b0a2020696e7472696e736963436c6173733a202270757265222c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020617267756d656e7454797065733a205b2a20636f72652d747970652d7265665d2c0a202072657475726e547970653a20636f72652d747970652d7265662c0a20206775617264537570706f72743a2066616c73652c0a2020666f6f747072696e7454656d706c6174653a20747374722c0a2020636f737454656d706c6174653a20747374722c0a20207772697465436c6173733a20226e6f6e65222c0a7d0a0a6566666563742d696e7472696e736963203d207b0a2020696e7472696e736963436c6173733a2022656666656374222c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020617267756d656e7454797065733a205b2a20636f72652d747970652d7265665d2c0a202072657475726e547970653a20636f72652d747970652d7265662c0a20206566666563744b696e643a206566666563742d6b696e642c0a20203b206d6170206b65796564206279206661696c75726520636f6f7264696e61746520286661696c7572652d6964656e74293b20746865206661696c75726520636f6f7264696e6174652069730a20203b20746865206b65792c206e6f7420612076616c7565206669656c642c20736f20756e697175656e657373206973207374727563747572616c0a20203b202845444943542d4142492d4641494c5552452d554e495155452d303031292e0a20206566666563744661696c757265733a207b202a206661696c7572652d6964656e74203d3e206566666563742d6661696c7572652d626f6479207d2c0a20206775617264537570706f72743a20626f6f6c2c0a2020666f6f747072696e7454656d706c6174653a20747374722c0a2020636f737454656d706c6174653a20747374722c0a20207772697465436c6173733a20227265616422202f202263726561746522202f2022656e7375726522202f2022617070656e6422202f20227265706c61636522202f0a20202020202020202020202020202264656c65746522202f2022637573746f6d222c0a202063616e5061727469636970617465496e41746f6d696347756172643a20626f6f6c2c0a7d0a0a3b206566666563742d6661696c7572652d626f64792c206566666563742d6b696e642c20617574686f726974792d636c6173732c20616e6420636f72652d747970652d7265662061726520646566696e65640a3b206f6e636520696e2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a3b202d2d2d2065646963742d617574686f726974792d66616374732e6364646c202d2d2d0a3b2065646963742d617574686f726974792d66616374732e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f722074686520666972737420636f6d70696c65722d636f6e7465787420617574686f726974792d666163747320646f63756d656e742e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a3b0a3b205468697320736368656d6120697320617373656d626c656420776974682065646963742d636f6d6d6f6e2e6364646c20736f20736f757263652e6469676573742075736573207468650a3b20736861726564207368613235362d6469676573742074797065642076616c75652e204a534f4e2069732061207265766965772f696e7075742072656e646572696e673a206974730a3b20607368613235363a3c3634206865783e6020736f75726365206469676573742069732070726f6a656374656420746f205b60736861323536602c203332207261772062797465735d206f6e0a3b2074686520776972652c20616e64206974732066616374206172726179732070726f6a65637420746f2074686520636f6f7264696e6174652d6b65796564206d6170732062656c6f772e0a0a617574686f726974792d6661637473203d207b0a202061706956657273696f6e3a202265646963742e617574686f726974792d66616374732f7631222c0a2020736f757263653a20617574686f726974792d666163742d736f757263652c0a20206f7065726174696f6e50726f66696c65733a207b202a2074737472203d3e20617574686f726974792d6f7065726174696f6e2d70726f66696c652d66616374207d2c0a20206566666563745772697465436c61737365733a207b202a2074737472203d3e20617574686f726974792d77726974652d636c617373207d2c0a2020627564676574733a207b202a2074737472203d3e20617574686f726974792d6275646765742d66616374207d2c0a7d0a0a617574686f726974792d666163742d736f75726365203d207b0a20206b696e643a20226c61777061636b22202f202274617267657450726f66696c65222c0a2020636f6f7264696e6174653a20747374722c0a20206469676573743a207368613235362d6469676573742c0a7d0a0a3b20546865206d6170206b65792069732074686520736f75726365206f7065726174696f6e2d70726f66696c6520636f6f7264696e6174652e204974206973206e6f7420726570656174656420696e0a3b207468652076616c75652c20736f2061206b657920616e6420656d62656464656420636f6f7264696e6174652063616e6e6f742064697361677265652e20416c6c6f7765642077726974650a3b20636c61737365732061726520612063616e6f6e6963616c206d61702d7365743a2074686520636c6173732069732074686520756e69717565206b657920616e64206e756c6c206973207468650a3b20756e6974206d61726b65722e2043616e6f6e6963616c2043424f52206669786573206b6579206f7264657220776974686f75742061207365636f6e64206f72646572696e672072756c652e0a617574686f726974792d6f7065726174696f6e2d70726f66696c652d66616374203d207b0a2020636f72653a20747374722c0a2020616c6c6f7765645772697465436c61737365733a207b202a20617574686f726974792d77726974652d636c617373203d3e206e756c6c207d2c0a7d0a0a3b20546865206566666563745772697465436c6173736573206d6170206b6579206973207468652073656d616e7469632065666665637420636f6f7264696e6174652e2054686520627564676574730a3b206d6170206b65792069732074686520736f757263652062756467657420636f6f7264696e6174652e2043616e6f6e6963616c2043424f52206d61702d6b657920756e697175656e6573730a3b206d616b6573206475706c6963617465206661637420636f6f7264696e61746573207374727563747572616c6c7920756e726570726573656e7461626c652e0a617574686f726974792d6275646765742d66616374203d207b0a20206d617853746570733a2075696e742c0a20206d6178416c6c6f636174656442797465733a2075696e742c0a20206d61784f757470757442797465733a2075696e742c0a7d0a0a3b20417574686f726974794661637473446f63756d656e7420763120696e74656e74696f6e616c6c792061636365707473206f6e6c792074686520777269746520636c6173736573207468650a3b2063757272656e7420636f6d70696c6572206d6f64656c2063616e20636f6e73756d652e2060637573746f6d602069732074686520736f6c6520763120637573746f6d207370656c6c696e673b0a3b20617262697472617279207461726765742d70726f66696c6520657874656e73696f6e20737472696e677320646f206e6f7420656e746572207468697320636f6d70696c657220706174682e0a617574686f726974792d77726974652d636c617373203d20226e6f6e6522202f20227265616422202f202263726561746522202f2022656e7375726522202f2022617070656e6422202f0a202020202020202020202020202020202020202020202020227265706c61636522202f202264656c65746522202f2022637573746f6d220a0a3b202d2d2d2065646963742d726573756c742d70726f6a656374696f6e2e6364646c202d2d2d0a3b20535044582d4c6963656e73652d4964656e7469666965723a204170616368652d322e300a3b2065646963742d726573756c742d70726f6a656374696f6e2e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f7220636f6d70696c65722d6f776e6564206170706c69636174696f6e2d726573756c742070726f6a656374696f6e732e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a0a726573756c742d70726f6a656374696f6e203d207b0a2020736368656d613a202265646963742e726573756c742d70726f6a656374696f6e2f7631222c0a20206f7065726174696f6e436f6f7264696e6174653a20626f756e6465642d70726f6a656374696f6e2d746578742c0a20206f7574707574547970653a20626f756e6465642d70726f6a656374696f6e2d746578742c0a20206d61784f757470757442797465733a2075696e74202e677420302c0a202065787072657373696f6e3a20726573756c742d70726f6a656374696f6e2d657870722c0a7d0a0a726573756c742d70726f6a656374696f6e2d65787072203d20726573756c742d70726f6a656374696f6e2d7265636f7264202f20726573756c742d70726f6a656374696f6e2d736f757263650a0a726573756c742d70726f6a656374696f6e2d7265636f7264203d207b0a20206b696e643a20227265636f7264222c0a20203b2054686520726f6f74207265636f726420636f756e7473206173206f6e65206f66207468652052757374206465636f6465722773203235362065787072657373696f6e206e6f6465732e0a20203b204e657374656420616767726567617465206e6f646520636f756e742072656d61696e7320616e20617574686f7269746174697665206465636f64657220636865636b2e0a20206669656c64733a207b20302a32353520626f756e6465642d70726f6a656374696f6e2d74657874203d3e20726573756c742d70726f6a656374696f6e2d65787072207d2c0a7d0a0a726573756c742d70726f6a656374696f6e2d736f75726365203d207b0a20206b696e643a2022736f75726365222c0a2020736f757263653a20726573756c742d70726f6a656374696f6e2d736f757263652d6b696e642c0a20203b204d617463686573204d41585f524553554c545f50524f4a454354494f4e5f504154485f5345474d454e545320696e2065646963742d73796e7461782e0a2020706174683a205b302a333220626f756e6465642d70726f6a656374696f6e2d746578745d2c0a7d0a0a726573756c742d70726f6a656374696f6e2d736f757263652d6b696e64203d0a20207b206b696e643a20226170706c69636174696f6e496e70757422207d202f0a20207b0a202020206b696e643a20226361706162696c697479526573756c74222c0a202020207374657049643a20626f756e6465642d70726f6a656374696f6e2d746578742c0a20207d0a0a626f756e6465642d70726f6a656374696f6e2d74657874203d2074737472202e73697a652028312e2e31303234290a0a3b202d2d2d2065646963742d7461726765742d69722e6364646c202d2d2d0a3b20535044582d4c6963656e73652d4964656e7469666965723a204170616368652d322e300a3b2065646963742d7461726765742d69722e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f72207468652045646963742d6f776e65642054617267657420495220617274696661637420656e76656c6f70652e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a3b0a3b205468697320736368656d6120697320617373656d626c656420776974682065646963742d636f6d6d6f6e2e6364646c20616e642065646963742d636f72652e6364646c2e2049740a3b2064656c696265726174656c792072657573657320436f72652065787072657373696f6e732c20707265646963617465732c20627564676574732c206c6f63616c207265666572656e6365732c0a3b206f62737472756374696f6e20726561736f6e732c20616e64206f62737472756374696f6e2061726d7320736f2074686520736368656d61206d617463686573207468652076616c75650a3b20656d6974746564206279207468652063616e6f6e6963616c2054617267657420495220656e636f64657220726174686572207468616e20726573746174696e672074686f73652074797065732e0a3b2049742064657363726962657320746865207374727563747572616c207368617065206f662076616c6964206c6f776572696e672d70726f6475636564206172746966616374732e205468650a3b206c6f776572696e6720616e6420656e636f64657220636f6e7472616374732073657061726174656c7920656e666f7263652073656d616e746963206964656e7469666965722072756c65730a3b20616e642063616e6f6e6963616c206f72646572696e672f64656475706c69636174696f6e20666f72207365742d6c696b652076616c7565732e0a0a3b2054617267657420495220656e636f64696e672072656a6563747320616e20656d707479207461726765742d70726f66696c6520636f6f7264696e617465206265666f72652062797465730a3b2065786973742c20736f207468697320726f6f74207469676874656e732074686520736861726564207374727563747572616c207265736f757263652d726566206163636f7264696e676c792e0a7461726765742d69722d7265736f757263652d726566203d207b0a202069643a2074737472202e7265676578702022283f73292e2b222c0a20206469676573743a207368613235362d6469676573742c0a7d0a0a7461726765742d69722d6172746966616374203d207461726765742d69722d636c6f7365642d6172746966616374202f207461726765742d69722d6c65676163792d61727469666163740a0a7461726765742d69722d61727469666163742d636f6d6d6f6e203d20280a20206b696e643a202274617267657449724172746966616374222c0a2020646f6d61696e3a20747374722c0a202074617267657450726f66696c653a207461726765742d69722d7265736f757263652d7265662c0a2020736f75726365436f7265436f6f7264696e6174653a2074737472202e7265676578702022283f73292e2b222c0a290a0a7461726765742d69722d636c6f7365642d6172746966616374203d207b0a20207461726765742d69722d61727469666163742d636f6d6d6f6e2c0a202073656d616e746963436c6f737572653a207461726765742d69722d73656d616e7469632d636c6f737572652c0a2020696e74656e74733a207b202a2074737472203d3e207461726765742d69722d696e74656e74207d2c0a7d0a0a7461726765742d69722d6c65676163792d6172746966616374203d207b0a20207461726765742d69722d61727469666163742d636f6d6d6f6e2c0a2020696e74656e74733a207b202a2074737472203d3e207461726765742d69722d6c65676163792d696e74656e74207d2c0a7d0a0a7461726765742d69722d73656d616e7469632d636c6f73757265203d207b0a2020736f75726365436f72653a207461726765742d69722d7265736f757263652d7265662c0a20206c61777061636b733a205b2a207461726765742d69722d7265736f757263652d7265665d2c0a7d0a0a7461726765742d69722d696e74656e74203d207b0a20207461726765742d69722d696e74656e742d636f6d6d6f6e2c0a20203f2062617369733a20636f72652d657870722c0a7d0a0a7461726765742d69722d6c65676163792d696e74656e74203d207b0a20207461726765742d69722d696e74656e742d636f6d6d6f6e2c0a7d0a0a7461726765742d69722d696e74656e742d636f6d6d6f6e203d20280a20206f7065726174696f6e50726f66696c653a20747374722c0a2020696e707574436f6e73747261696e74733a205b2a20696e7075742d636f6e73747261696e745d2c0a2020636f72654576616c756174696f6e4275646765743a20636f72652d6275646765742c0a2020726571756972656d656e74733a205b2a207461726765742d69722d726571756972656d656e745d2c0a202073746570733a205b2a207461726765742d69722d737465705d2c0a2020726573756c743a20636f72652d657870722c0a290a0a7461726765742d69722d726571756972656d656e74203d207b0a202069643a20747374722c0a20207072656469636174653a20636f72652d7072656469636174652c0a20206f6e4661696c7572653a20726571756972652d6661696c7572652d61726d2c0a7d0a0a7461726765742d69722d73746570203d207b0a202069643a20747374722c0a202062696e64696e673a206c6f63616c2d7265662c0a20206566666563743a20747374722c0a2020746172676574496e7472696e7369633a20747374722c0a2020696e7075743a20636f72652d657870722c0a20206f62737472756374696f6e4661696c757265733a205b2a206661696c7572652d6964656e745d2c0a20206f62737472756374696f6e41726d733a207b202a206661696c7572652d6964656e74203d3e206f62737472756374696f6e2d61726d207d2c0a7d0a", + "rawSha256": "ff5405708185e0bcf33dac263000fcb772c79e21145ad69da7cad0692e1a9552" }, "contracts": [ {"contract": "authority-facts", "rootRule": "authority-facts"}, @@ -13,6 +13,7 @@ {"contract": "lawpack-exports", "rootRule": "lawpack-exports"}, {"contract": "lawpack-manifest", "rootRule": "lawpack-manifest"}, {"contract": "lowering-requirements", "rootRule": "lowering-requirements"}, + {"contract": "result-projection", "rootRule": "result-projection"}, {"contract": "target-ir-artifact", "rootRule": "target-ir-artifact"}, {"contract": "target-profile-intrinsics", "rootRule": "intrinsics-document"}, {"contract": "target-profile-manifest", "rootRule": "target-profile-manifest"}, @@ -23,6 +24,7 @@ {"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.result-projection.artifact/v1", "rootRule": "result-projection"}, {"domain": "edict.target-ir.artifact/v1", "rootRule": "target-ir-artifact"}, {"domain": "edict.target-profile/v1", "rootRule": "target-profile-manifest"} ], 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 index 3a497b03..659b424a 100644 --- 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 @@ -539,6 +539,12 @@ "domain": "edict.lowering-requirements/v1", "schemaRole": "schema.echo-provider-artifacts" }, + { + "role": "result-projection.echo-operation", + "kind": "auxiliary", + "domain": "edict.result-projection.artifact/v1", + "schemaRole": "schema.echo-provider-artifacts" + }, { "role": "source.echo-operation", "kind": "auxiliary", @@ -771,6 +777,12 @@ "format": "selfContainedCddlV1", "rootRule": "lowering-requirements" }, + { + "domain": "edict.result-projection.artifact/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "result-projection" + }, { "domain": "edict.source/v1", "schemaRole": "schema.echo-provider-artifacts", @@ -790,4 +802,4 @@ "rootRule": "target-profile-manifest" } ] -} \ No newline at end of file +} 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 8ba4de4e..fc90817b 100644 Binary files a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm and b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm differ 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 284ccec0..b6c120b0 100644 Binary files a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm and b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm differ 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 da7bace8..632d8807 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:e2a6a539a7156296c18ff1bc02f80dcabf62b42bb4314d0737527869e43986d6"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:ce1af559551f8b8242c4b290b620c5a28323b9e43f8bc6bb161a191001b6f4b9"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:8c570362671a0b1cd1a992d8210e4a90ffd153ad06dcdf1e0cb36033cc971e2c"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:1b105d1b1f6cdf5fecdef98b7adeb238525047d43581fe9fd8c44fd213e1788e"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:6b9076ae02730797fddf60a93606df3de245a1c6bfbd845486799b7310d002a2"}],"generationInputDigest":"sha256:49646ba46efe7b070ff1605bf7b148e6d35611a570015e9b08fa7d30206ec7c7","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:a5d5ea82a9e64aa78c4a44204d3e8919c1c590febb967f1d31639fdc2a20a96c"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:f78dc8bb32f04f3e246f57e4228077c2a243827dd243525b9bd2e1d81dfa07ff"}]} \ 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:e2a6a539a7156296c18ff1bc02f80dcabf62b42bb4314d0737527869e43986d6"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:ce1af559551f8b8242c4b290b620c5a28323b9e43f8bc6bb161a191001b6f4b9"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:8c570362671a0b1cd1a992d8210e4a90ffd153ad06dcdf1e0cb36033cc971e2c"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:1b105d1b1f6cdf5fecdef98b7adeb238525047d43581fe9fd8c44fd213e1788e"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:730ce72f6658fe8cc9302221c32ad5992492e190674ddd69c1b164749d2bb669"}],"generationInputDigest":"sha256:57f5f67172544014af9c92e658301b9fcec69fd77fba9d251b258b59e3591380","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:ff5405708185e0bcf33dac263000fcb772c79e21145ad69da7cad0692e1a9552"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:e31d0452bf9d8ba84eaa1ce8c09fa1c25f740decd0ab08cd9c2fde533bdef1fa"}]} \ 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 e333e6dc..0ba69ca3 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:e2a6a539a7156296c18ff1bc02f80dcabf62b42bb4314d0737527869e43986d6"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:ce1af559551f8b8242c4b290b620c5a28323b9e43f8bc6bb161a191001b6f4b9"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:8c570362671a0b1cd1a992d8210e4a90ffd153ad06dcdf1e0cb36033cc971e2c"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:1b105d1b1f6cdf5fecdef98b7adeb238525047d43581fe9fd8c44fd213e1788e"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:6b9076ae02730797fddf60a93606df3de245a1c6bfbd845486799b7310d002a2"}],"generationInputDigest":"sha256:49646ba46efe7b070ff1605bf7b148e6d35611a570015e9b08fa7d30206ec7c7","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52","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:d448084da79f0cca20fa538f188e414d37192be88b127facc0056a4571da7741","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:a5d5ea82a9e64aa78c4a44204d3e8919c1c590febb967f1d31639fdc2a20a96c"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:f78dc8bb32f04f3e246f57e4228077c2a243827dd243525b9bd2e1d81dfa07ff"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:e2a6a539a7156296c18ff1bc02f80dcabf62b42bb4314d0737527869e43986d6"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:ce1af559551f8b8242c4b290b620c5a28323b9e43f8bc6bb161a191001b6f4b9"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:8c570362671a0b1cd1a992d8210e4a90ffd153ad06dcdf1e0cb36033cc971e2c"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:1b105d1b1f6cdf5fecdef98b7adeb238525047d43581fe9fd8c44fd213e1788e"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:730ce72f6658fe8cc9302221c32ad5992492e190674ddd69c1b164749d2bb669"}],"generationInputDigest":"sha256:57f5f67172544014af9c92e658301b9fcec69fd77fba9d251b258b59e3591380","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346","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:998426658fbcbd44bff4f28d0d4c82df7aaf05bdbcdb736db9cf481a1948ec82","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:ff5405708185e0bcf33dac263000fcb772c79e21145ad69da7cad0692e1a9552"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:e31d0452bf9d8ba84eaa1ce8c09fa1c25f740decd0ab08cd9c2fde533bdef1fa"}]} \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl index 32ecdc59..ea161b3d 100644 --- a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl @@ -583,7 +583,7 @@ lawpack-adapter-budget = { } lawpack-adapter-write-class = "none" / "read" / "create" / "ensure" / - "append" / "modify" / "delete" + "append" / "replace" / "delete" / "custom" ; failure-ident is defined in edict-common.cddl. @@ -789,6 +789,45 @@ authority-budget-fact = { authority-write-class = "none" / "read" / "create" / "ensure" / "append" / "replace" / "delete" / "custom" +; --- edict-result-projection.cddl --- +; SPDX-License-Identifier: Apache-2.0 +; edict-result-projection.cddl +; Canonical schema for compiler-owned application-result projections. +; Authoritative byte encoding: edict.canonical-cbor/v1. + +result-projection = { + schema: "edict.result-projection/v1", + operationCoordinate: bounded-projection-text, + outputType: bounded-projection-text, + maxOutputBytes: uint .gt 0, + expression: result-projection-expr, +} + +result-projection-expr = result-projection-record / result-projection-source + +result-projection-record = { + kind: "record", + ; The root record counts as one of the Rust decoder's 256 expression nodes. + ; Nested aggregate node count remains an authoritative decoder check. + fields: { 0*255 bounded-projection-text => result-projection-expr }, +} + +result-projection-source = { + kind: "source", + source: result-projection-source-kind, + ; Matches MAX_RESULT_PROJECTION_PATH_SEGMENTS in edict-syntax. + path: [0*32 bounded-projection-text], +} + +result-projection-source-kind = + { kind: "applicationInput" } / + { + kind: "capabilityResult", + stepId: bounded-projection-text, + } + +bounded-projection-text = tstr .size (1..1024) + ; --- edict-target-ir.cddl --- ; SPDX-License-Identifier: Apache-2.0 ; edict-target-ir.cddl @@ -1056,6 +1095,7 @@ echo-nonempty-tstr = tstr .regexp "(?s).+" edict-source-bytes = bstr echo-operation-package = { + "application_result_projection": echo-operation-application-result-projection, "application_basis_schema_identity": bstr .size 32, "authority_profile_identity": bstr .size 32, "budget_ceiling": echo-operation-budget, @@ -1076,6 +1116,28 @@ echo-operation-package = { "target_profile_identity": bstr .size 32, } +echo-operation-application-result-projection = { + "application_input_node_key_path": [* echo-nonempty-tstr], + "application_input_replacement_path": [* echo-nonempty-tstr], + "artifact_bytes": bstr, + "artifact_identity": bstr .size 32, + "runtime_expression": echo-operation-result-expression, +} + +echo-operation-result-expression = + echo-operation-result-record / echo-operation-result-source + +echo-operation-result-record = { + kind: "record", + fields: { * echo-nonempty-tstr => echo-operation-result-expression }, +} + +echo-operation-result-source = { + kind: "source", + path: [* echo-nonempty-tstr], + source: { kind: "applicationInput" }, +} + echo-operation-budget = { "read_bytes": uint, steps: 1..18446744073709551615, @@ -1115,6 +1177,7 @@ echo-operation-lowering-configuration = { echo-operation-package-verifier-report = { apiVersion: "echo.operation-package-verifier-report/v1", + applicationResultProjection: resource-ref, package: resource-ref, targetIr: resource-ref, outcome: "accepted" / "rejected", 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 4fabbf1c..729f3463 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:a7ab6bfbbedc3a6b61a8559dc6506cfc3d2836b46dac3cc825e5b05b16b94fa5" + "digest": "sha256:fe1a1f1c05e88bb3caeadb2d77fb17a906a4819674c50d75b2dcaca0fb6058ec" }, "artifacts": [ { @@ -17,11 +17,11 @@ "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070" + "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52" + "digest": "sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346" } } }, @@ -36,11 +36,11 @@ "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070" + "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52" + "digest": "sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346" } } }, @@ -55,11 +55,11 @@ "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070" + "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52" + "digest": "sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346" } } }, @@ -74,11 +74,11 @@ "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070" + "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52" + "digest": "sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346" } } }, @@ -87,13 +87,13 @@ "artifactKind": "lowerer", "resource": { "coordinate": "echo.dpo.lowerer/component@1", - "digest": "sha256:08277d4ba7d98e0b143c06c208abc306f133bda510caa5393da08aa490334a6e" + "digest": "sha256:dfd14015705ff555a7efdb3787ddb0f8b4f304168a9a0ebf324fd25d430bf5cd" }, "source": { "kind": "component", "component": { "coordinate": "echo.dpo.lowerer/component@1", - "digest": "sha256:08277d4ba7d98e0b143c06c208abc306f133bda510caa5393da08aa490334a6e" + "digest": "sha256:dfd14015705ff555a7efdb3787ddb0f8b4f304168a9a0ebf324fd25d430bf5cd" } } }, @@ -102,17 +102,17 @@ "artifactKind": "generationProvenance", "resource": { "coordinate": "echo.edict-provider-generation-provenance@1", - "digest": "sha256:83840aab907b1189482a92f70a405602bf76715dc8e4fbffdc543db2d6151019" + "digest": "sha256:720076fdd6462ab5500e944408199a141d07eca8e4e73d542e01e7fcdc715ac4" }, "source": { "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070" + "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52" + "digest": "sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346" } } }, @@ -121,17 +121,17 @@ "artifactKind": "reviewArtifact", "resource": { "coordinate": "echo.edict-provider-generation-review@1", - "digest": "sha256:26b954ae9e2220a339c2dfb6673615aafb1567be19aa7ee38eefa6b34e18897d" + "digest": "sha256:592af76dab9f354a4afb663365990e8a14bf07c1721cdc2242319ad457ee5e2b" }, "source": { "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070" + "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52" + "digest": "sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346" } } }, @@ -140,17 +140,17 @@ "artifactKind": "artifactSchema", "resource": { "coordinate": "echo.provider-artifacts.cddl@1", - "digest": "sha256:6b9076ae02730797fddf60a93606df3de245a1c6bfbd845486799b7310d002a2" + "digest": "sha256:730ce72f6658fe8cc9302221c32ad5992492e190674ddd69c1b164749d2bb669" }, "source": { "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070" + "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52" + "digest": "sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346" } } }, @@ -165,11 +165,11 @@ "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070" + "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52" + "digest": "sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346" } } }, @@ -178,13 +178,13 @@ "artifactKind": "verifier", "resource": { "coordinate": "echo.dpo.verifier/component@1", - "digest": "sha256:744a511137608634b88abf7bd7e61da9bf81a5cacff7b190fc2530c346ba36cc" + "digest": "sha256:279738ffeea40027eb493c15e873b87cf3aa0677a57f9f03fb824698e532322f" }, "source": { "kind": "component", "component": { "coordinate": "echo.dpo.verifier/component@1", - "digest": "sha256:744a511137608634b88abf7bd7e61da9bf81a5cacff7b190fc2530c346ba36cc" + "digest": "sha256:279738ffeea40027eb493c15e873b87cf3aa0677a57f9f03fb824698e532322f" } } } @@ -352,6 +352,12 @@ "format": "selfContainedCddlV1", "rootRule": "lowering-requirements" }, + { + "domain": "edict.result-projection.artifact/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "result-projection" + }, { "domain": "edict.source/v1", "schemaRole": "schema.echo-provider-artifacts", diff --git a/crates/echo-wesley-gen/assets/v1/repository/Cargo.lock.source b/crates/echo-wesley-gen/assets/v1/repository/Cargo.lock.source index 585e918f..4f4d3d33 100644 --- a/crates/echo-wesley-gen/assets/v1/repository/Cargo.lock.source +++ b/crates/echo-wesley-gen/assets/v1/repository/Cargo.lock.source @@ -2218,6 +2218,7 @@ dependencies = [ "hex", "proptest", "rustc-hash 2.1.1", + "sha2", "thiserror 1.0.69", "warp-math", ] diff --git a/crates/echo-wesley-gen/src/provider_artifacts.rs b/crates/echo-wesley-gen/src/provider_artifacts.rs index 48f09bbb..a0bf5eea 100644 --- a/crates/echo-wesley-gen/src/provider_artifacts.rs +++ b/crates/echo-wesley-gen/src/provider_artifacts.rs @@ -233,6 +233,7 @@ echo-nonempty-tstr = tstr .regexp "(?s).+" edict-source-bytes = bstr echo-operation-package = { + "application_result_projection": echo-operation-application-result-projection, "application_basis_schema_identity": bstr .size 32, "authority_profile_identity": bstr .size 32, "budget_ceiling": echo-operation-budget, @@ -253,6 +254,28 @@ echo-operation-package = { "target_profile_identity": bstr .size 32, } +echo-operation-application-result-projection = { + "application_input_node_key_path": [* echo-nonempty-tstr], + "application_input_replacement_path": [* echo-nonempty-tstr], + "artifact_bytes": bstr, + "artifact_identity": bstr .size 32, + "runtime_expression": echo-operation-result-expression, +} + +echo-operation-result-expression = + echo-operation-result-record / echo-operation-result-source + +echo-operation-result-record = { + kind: "record", + fields: { * echo-nonempty-tstr => echo-operation-result-expression }, +} + +echo-operation-result-source = { + kind: "source", + path: [* echo-nonempty-tstr], + source: { kind: "applicationInput" }, +} + echo-operation-budget = { "read_bytes": uint, steps: 1..18446744073709551615, @@ -292,6 +315,7 @@ echo-operation-lowering-configuration = { echo-operation-package-verifier-report = { apiVersion: "echo.operation-package-verifier-report/v1", + applicationResultProjection: resource-ref, package: resource-ref, targetIr: resource-ref, outcome: "accepted" / "rejected", diff --git a/crates/echo-wesley-gen/src/provider_contract_pack.rs b/crates/echo-wesley-gen/src/provider_contract_pack.rs index 9115361e..b7edff3e 100644 --- a/crates/echo-wesley-gen/src/provider_contract_pack.rs +++ b/crates/echo-wesley-gen/src/provider_contract_pack.rs @@ -32,22 +32,23 @@ pub const EDICT_PROVIDER_CONTRACT_PACK_LICENSE: &str = "Apache-2.0"; /// SHA-256 of the admitted self-contained CDDL bytes. pub const EDICT_PROVIDER_CONTRACT_PACK_SCHEMA_SHA256: &str = - "a5d5ea82a9e64aa78c4a44204d3e8919c1c590febb967f1d31639fdc2a20a96c"; + "ff5405708185e0bcf33dac263000fcb772c79e21145ad69da7cad0692e1a9552"; /// SHA-256 of the admitted Edict publication manifest bytes. pub const EDICT_PROVIDER_CONTRACT_PACK_MANIFEST_SHA256: &str = - "f78dc8bb32f04f3e246f57e4228077c2a243827dd243525b9bd2e1d81dfa07ff"; + "e31d0452bf9d8ba84eaa1ce8c09fa1c25f740decd0ab08cd9c2fde533bdef1fa"; /// Maximum manifest size parsed at the contract-pack authority boundary. -pub const EDICT_PROVIDER_CONTRACT_PACK_MANIFEST_MAX_BYTES: usize = 65_797; +pub const EDICT_PROVIDER_CONTRACT_PACK_MANIFEST_MAX_BYTES: usize = 68_359; -const EXPECTED_CONTRACTS: [(&str, &str); 10] = [ +const EXPECTED_CONTRACTS: [(&str, &str); 11] = [ ("authority-facts", "authority-facts"), ("core-module", "core-module"), ("lawpack-adapter", "lawpack-adapter"), ("lawpack-exports", "lawpack-exports"), ("lawpack-manifest", "lawpack-manifest"), ("lowering-requirements", "lowering-requirements"), + ("result-projection", "result-projection"), ("target-ir-artifact", "target-ir-artifact"), ("target-profile-intrinsics", "intrinsics-document"), ("target-profile-manifest", "target-profile-manifest"), @@ -57,11 +58,12 @@ const EXPECTED_CONTRACTS: [(&str, &str); 10] = [ ), ]; -const EXPECTED_DOMAINS: [(&str, &str); 6] = [ +const EXPECTED_DOMAINS: [(&str, &str); 7] = [ ("edict.authority-facts/v1", "authority-facts"), ("edict.core.module/v1", "core-module"), ("edict.lawpack/v1", "lawpack-manifest"), ("edict.lowering-requirements/v1", "lowering-requirements"), + ("edict.result-projection.artifact/v1", "result-projection"), ("edict.target-ir.artifact/v1", "target-ir-artifact"), ("edict.target-profile/v1", "target-profile-manifest"), ]; diff --git a/crates/echo-wesley-gen/src/provider_package.rs b/crates/echo-wesley-gen/src/provider_package.rs index 6330d9e5..e78b4aad 100644 --- a/crates/echo-wesley-gen/src/provider_package.rs +++ b/crates/echo-wesley-gen/src/provider_package.rs @@ -49,7 +49,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 = 30; +const EXPECTED_SCHEMA_BINDING_COUNT: usize = 31; const EXPECTED_MEMBER_COUNT: usize = 24; const EXPECTED_FILE_COUNT: usize = 25; const MAX_COMPONENT_BYTES: usize = 16 * 1024 * 1024; @@ -368,7 +368,7 @@ pub struct ProviderManifestV1 { pub provider: ProviderManifestResourceRefV1, /// Ten exact generated/component artifact routes. pub artifacts: Vec, - /// Twenty-four exact immutable schema-domain bindings. + /// Exact immutable schema-domain bindings. pub schema_bindings: Vec, } @@ -2006,6 +2006,7 @@ fn schema_binding_specs() -> [(&'static str, &'static str); EXPECTED_SCHEMA_BIND ("edict.lawpack-exports/v1", "lawpack-exports"), ("edict.lawpack/v1", "lawpack-manifest"), ("edict.lowering-requirements/v1", "lowering-requirements"), + ("edict.result-projection.artifact/v1", "result-projection"), ("edict.source/v1", "edict-source-bytes"), ("edict.target-ir.artifact/v1", "target-ir-artifact"), ("edict.target-profile/v1", "target-profile-manifest"), diff --git a/crates/echo-wesley-gen/src/provider_semantics.rs b/crates/echo-wesley-gen/src/provider_semantics.rs index e4fb7d4d..583c0b3e 100644 --- a/crates/echo-wesley-gen/src/provider_semantics.rs +++ b/crates/echo-wesley-gen/src/provider_semantics.rs @@ -3373,7 +3373,7 @@ fn validate_invocation_schema_bindings( (InvocationInputKind::AuthorityFacts, 2), (InvocationInputKind::LowerabilityFacts, 1), (InvocationInputKind::TargetIr, 2), - (InvocationInputKind::Auxiliary, 5), + (InvocationInputKind::Auxiliary, 6), ] { let actual = source .invocation_inputs @@ -3663,6 +3663,7 @@ fn expected_input_domain(input: &InvocationInputDeclaration) -> &'static str { "adapter.echo-operation" => "edict.lawpack-adapter/v1", "exports.echo-operation" => "edict.lawpack-exports/v1", "executable-operation-package.echo" => "echo.operation-package/v1", + "result-projection.echo-operation" => "edict.result-projection.artifact/v1", "source.echo-operation" => "edict.source/v1", "target-configuration.echo-operation" => "echo.operation-lowering-configuration/v1", _ => "", @@ -3714,6 +3715,7 @@ fn expected_schema_root(domain: &str) -> Option<&'static str> { "edict.lawpack-exports/v1" => Some("lawpack-exports"), "edict.lawpack/v1" => Some("lawpack-manifest"), "edict.lowering-requirements/v1" => Some("lowering-requirements"), + "edict.result-projection.artifact/v1" => Some("result-projection"), "edict.source/v1" => Some("edict-source-bytes"), "edict.target-profile/v1" => Some("target-profile-manifest"), "edict.target-ir.artifact/v1" => Some("target-ir-artifact"), diff --git a/crates/echo-wesley-gen/tests/provider_contract_pack.rs b/crates/echo-wesley-gen/tests/provider_contract_pack.rs index 8bc38c03..6dcbb706 100644 --- a/crates/echo-wesley-gen/tests/provider_contract_pack.rs +++ b/crates/echo-wesley-gen/tests/provider_contract_pack.rs @@ -12,11 +12,12 @@ const CONTRACT_CDDL: &[u8] = include_bytes!("../assets/v1/edict-provider/contracts/v1/edict-provider-contracts.cddl"); const CONTRACT_MANIFEST: &[u8] = include_bytes!("../assets/v1/edict-provider/contracts/v1/manifest.json"); -const DOMAIN_ROOTS: [(&str, &str); 6] = [ +const DOMAIN_ROOTS: [(&str, &str); 7] = [ ("edict.authority-facts/v1", "authority-facts"), ("edict.core.module/v1", "core-module"), ("edict.lawpack/v1", "lawpack-manifest"), ("edict.lowering-requirements/v1", "lowering-requirements"), + ("edict.result-projection.artifact/v1", "result-projection"), ("edict.target-ir.artifact/v1", "target-ir-artifact"), ("edict.target-profile/v1", "target-profile-manifest"), ]; @@ -47,10 +48,10 @@ fn checked_edict_provider_contract_pack_is_admitted() { assert_eq!(pack.license(), "Apache-2.0"); assert_eq!( pack.schema_sha256(), - "a5d5ea82a9e64aa78c4a44204d3e8919c1c590febb967f1d31639fdc2a20a96c" + "ff5405708185e0bcf33dac263000fcb772c79e21145ad69da7cad0692e1a9552" ); - assert_eq!(pack.contract_count(), 10); - assert_eq!(pack.domain_count(), 6); + assert_eq!(pack.contract_count(), 11); + assert_eq!(pack.domain_count(), 7); assert_eq!(pack.resource_count(), 5); assert_eq!(pack.schema_bytes(), CONTRACT_CDDL); assert_eq!(pack.manifest_bytes(), CONTRACT_MANIFEST); @@ -85,7 +86,7 @@ fn tampered_contract_cddl_has_stable_failure_kind() { error.to_string(), concat!( "provider contract pack schema-bytes-mismatch: schema.bytesHex -> ", - "a5d5ea82a9e64aa78c4a44204d3e8919c1c590febb967f1d31639fdc2a20a96c" + "ff5405708185e0bcf33dac263000fcb772c79e21145ad69da7cad0692e1a9552" ) ); } diff --git a/crates/echo-wesley-gen/tests/provider_package.rs b/crates/echo-wesley-gen/tests/provider_package.rs index bf3f576c..393b25fc 100644 --- a/crates/echo-wesley-gen/tests/provider_package.rs +++ b/crates/echo-wesley-gen/tests/provider_package.rs @@ -65,7 +65,7 @@ const SEMANTIC_DIGEST: &str = const RELEASE_DIGEST: &str = "sha256:c39449495281b51f978468d08c21e93bcfa423176063b41675da61e4674b0066"; const PACKAGE_ARTIFACT_SHA256: &str = - "a7ab6bfbbedc3a6b61a8559dc6506cfc3d2836b46dac3cc825e5b05b16b94fa5"; + "fe1a1f1c05e88bb3caeadb2d77fb17a906a4819674c50d75b2dcaca0fb6058ec"; const OTHER_PACKAGE_ARTIFACT_SHA256: &str = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"; @@ -305,7 +305,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(), 30); + assert_eq!(package.manifest().schema_bindings.len(), 31); assert_eq!( package .manifest() diff --git a/crates/echo-wesley-gen/tests/provider_package_corpus.rs b/crates/echo-wesley-gen/tests/provider_package_corpus.rs index 94cc1698..188a8e5e 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:a7ab6bfbbedc3a6b61a8559dc6506cfc3d2836b46dac3cc825e5b05b16b94fa5"; + "sha256:fe1a1f1c05e88bb3caeadb2d77fb17a906a4819674c50d75b2dcaca0fb6058ec"; const EXPECTED_MANIFEST_RAW_SHA256: &str = - "59933c7c7ae4873b6dc0f64151951d6df095e8056995a8d4d93cf7917a43ac5a"; + "49bf01c6c2a7c5295d011e58b9b2a6e0c0436f067a1eb94144dbe27cdad3fef2"; const PACKAGE_PATHS: [&str; 25] = [ "components/lowerer.echo-dpo.component.wasm", diff --git a/crates/echo-wesley-gen/tests/provider_semantic_source.rs b/crates/echo-wesley-gen/tests/provider_semantic_source.rs index 4db929c9..7c76879a 100644 --- a/crates/echo-wesley-gen/tests/provider_semantic_source.rs +++ b/crates/echo-wesley-gen/tests/provider_semantic_source.rs @@ -574,6 +574,11 @@ fn checked_echo_provider_semantic_source_validates() { InvocationInputKind::LowerabilityFacts, "edict.lowering-requirements/v1", ), + ( + "result-projection.echo-operation", + InvocationInputKind::Auxiliary, + "edict.result-projection.artifact/v1", + ), ( "source.echo-operation", InvocationInputKind::Auxiliary, @@ -656,6 +661,7 @@ fn checked_echo_provider_semantic_source_validates() { ("edict.lawpack-exports/v1", "lawpack-exports"), ("edict.lawpack/v1", "lawpack-manifest"), ("edict.lowering-requirements/v1", "lowering-requirements"), + ("edict.result-projection.artifact/v1", "result-projection",), ("edict.source/v1", "edict-source-bytes"), ("edict.target-ir.artifact/v1", "target-ir-artifact"), ("edict.target-profile/v1", "target-profile-manifest"), diff --git a/crates/warp-core/Cargo.toml b/crates/warp-core/Cargo.toml index 7504ab5b..2cda23ab 100644 --- a/crates/warp-core/Cargo.toml +++ b/crates/warp-core/Cargo.toml @@ -20,6 +20,7 @@ bytes = "1.0" thiserror = "1.0" hex = "0.4" rustc-hash = "2.1.1" +sha2 = "0.10" echo-wasm-abi = { workspace = true } echo-runtime-schema = { workspace = true } echo-registry-api = { workspace = true } diff --git a/crates/warp-core/src/echo_operation.rs b/crates/warp-core/src/echo_operation.rs index cb4afbfd..fd62bcd3 100644 --- a/crates/warp-core/src/echo_operation.rs +++ b/crates/warp-core/src/echo_operation.rs @@ -23,9 +23,10 @@ use std::{ use blake3::Hasher; use bytes::Bytes; use echo_edict_canonical::{ - decode_canonical_cbor_v1, encode_canonical_cbor_v1, CanonicalValueError, - CanonicalValueErrorKind, CanonicalValueV1, + decode_canonical_cbor_v1, digest_canonical_value_bytes_v1, encode_canonical_cbor_v1, + CanonicalValueError, CanonicalValueErrorKind, CanonicalValueV1, }; +use sha2::{Digest as _, Sha256}; use thiserror::Error; use crate::{ @@ -60,6 +61,8 @@ const APPLICATION_BASIS_SCHEMA: &str = "echo.operation.basis.anchored-node-alpha const TARGET_PROFILE: &str = "echo.operation-target.anchored-node-alpha-cas/v1"; const CREATE_INVOCATION_SCHEMA: &str = "echo.operation-invocation.anchored-node-alpha-create-if-absent/v1"; +const PROJECTED_CREATE_INVOCATION_SCHEMA: &str = + "echo.operation-invocation.anchored-node-alpha-create-if-absent-projected/v1"; const CREATE_PROGRAM_KIND: &str = "anchored-node-attachment-create-if-absent/v1"; const CREATE_FOOTPRINT_CONTRACT: &str = "anchored-node-alpha-create-if-absent-exact/v1"; const CREATE_INPUT_SCHEMA: &str = "echo.operation.input.anchored-node-alpha-create-if-absent/v1"; @@ -102,6 +105,8 @@ const PREPARATION_ID_DOMAIN: &[u8] = b"echo:operation-preparation:v1\0"; const RESULT_ID_DOMAIN: &[u8] = b"echo:operation-result:v1\0"; const CREATE_RESULT_ID_DOMAIN: &[u8] = b"echo:operation-result-anchored-node-alpha-create-if-absent:v1\0"; +const PROJECTED_CREATE_RESULT_ID_DOMAIN: &[u8] = + b"echo:operation-result-anchored-node-alpha-create-if-absent-projected:v1\0"; const OBSTRUCTION_ID_DOMAIN: &[u8] = b"echo:operation-obstruction:v1\0"; const TERMINAL_OUTCOME_ID_DOMAIN: &[u8] = b"echo:operation-terminal-outcome:v1\0"; const ATOM_VALUE_DOMAIN: &[u8] = b"echo:operation-atom-value:v1\0"; @@ -116,6 +121,16 @@ const COMPOSITION_DIGEST_DOMAIN: &[u8] = b"echo:operation-singleton-composition: const PLAN_DIGEST_DOMAIN: &[u8] = b"echo:operation-plan:v1\0"; const REWRITES_DIGEST_DOMAIN: &[u8] = b"echo:operation-rewrites:v1\0"; const GENESIS_COMMIT_DOMAIN: &[u8] = b"echo:operation-genesis-commit:v1\0"; +const RESULT_PROJECTION_DOMAIN: &str = "edict.result-projection.artifact/v1"; +const RESULT_PROJECTION_SCHEMA: &str = "edict.result-projection/v1"; +const APPLICATION_RESULT_SCHEMA: &str = "echo.operation-application-result/v1"; +const APPLICATION_RESULT_ID_DOMAIN: &[u8] = b"echo:operation-application-result:v1\0"; +const MAX_RESULT_PROJECTION_NODES: usize = 256; +const MAX_RESULT_PROJECTION_PATH_SEGMENTS: usize = 32; +const MAX_RESULT_PROJECTION_TEXT_BYTES: usize = 1_024; +const MAX_RESULT_PROJECTION_ARTIFACT_BYTES: usize = 64 * 1_024; +const MAX_APPLICATION_INPUT_BYTES: usize = 64 * 1_024; +const MAX_APPLICATION_RESULT_BYTES: u64 = 64 * 1_024; /// Process-local capability proving that admission, evaluation, and commit are /// owned by the same Echo runtime instance. @@ -940,6 +955,686 @@ impl EchoOperationSemanticClosureV1 { } } +#[derive(Clone, Debug, PartialEq, Eq)] +enum EchoOperationResultExpressionV1 { + Record(BTreeMap), + ApplicationInputPath(Vec), +} + +impl EchoOperationResultExpressionV1 { + fn from_runtime_value( + value: CanonicalValueV1, + nodes: &mut usize, + ) -> Result { + *nodes = nodes + .checked_add(1) + .ok_or_else(|| invalid_structure("result projection node count overflowed"))?; + if *nodes > MAX_RESULT_PROJECTION_NODES { + return Err(invalid_structure( + "result projection exceeds the expression-node bound", + )); + } + let mut fields = text_map(value)?; + let kind = take_text(&mut fields, "kind")?; + match kind.as_str() { + "record" => { + require_field_names(&fields, &["fields"])?; + let field_values = text_map(take_field(&mut fields, "fields")?)?; + let mut result = BTreeMap::new(); + for (name, expression) in field_values { + validate_projection_text(&name)?; + result.insert(name, Self::from_runtime_value(expression, nodes)?); + } + Ok(Self::Record(result)) + } + "source" => { + require_field_names(&fields, &["path", "source"])?; + let mut source = exact_text_map(take_field(&mut fields, "source")?, &["kind"])?; + require_text(&mut source, "kind", "applicationInput")?; + Ok(Self::ApplicationInputPath(take_projection_path( + &mut fields, + "path", + )?)) + } + _ => Err(invalid_structure( + "result projection contains an unsupported runtime expression", + )), + } + } + + fn to_value(&self) -> CanonicalValueV1 { + match self { + Self::Record(fields) => map_value([ + ( + "fields", + CanonicalValueV1::Map( + fields + .iter() + .map(|(name, expression)| (text_value(name), expression.to_value())) + .collect(), + ), + ), + ("kind", text_value("record")), + ]), + Self::ApplicationInputPath(path) => map_value([ + ("kind", text_value("source")), + ( + "path", + CanonicalValueV1::Array( + path.iter().map(|segment| text_value(segment)).collect(), + ), + ), + ( + "source", + map_value([("kind", text_value("applicationInput"))]), + ), + ]), + } + } + + fn evaluate( + &self, + application_input: &CanonicalValueV1, + ) -> Result { + match self { + Self::Record(fields) => Ok(CanonicalValueV1::Map( + fields + .iter() + .map(|(name, expression)| { + Ok((text_value(name), expression.evaluate(application_input)?)) + }) + .collect::, EchoOperationArtifactErrorV1>>()?, + )), + Self::ApplicationInputPath(path) => { + value_at_projection_path(application_input, path).cloned() + } + } + } + + fn encoded_len_with_limit( + &self, + application_input: &CanonicalValueV1, + limit: usize, + ) -> Result { + match self { + Self::Record(fields) => { + let mut encoded_len = + bounded_projection_len(0, canonical_map_header_len(fields.len()), limit)?; + for (name, expression) in fields { + let encoded_name = + encode_canonical_cbor_v1(&text_value(name)).map_err(canonical_error)?; + encoded_len = bounded_projection_len(encoded_len, encoded_name.len(), limit)?; + let remaining = limit + .checked_sub(encoded_len) + .ok_or_else(projected_result_exceeds_bound)?; + let expression_len = + expression.encoded_len_with_limit(application_input, remaining)?; + encoded_len = bounded_projection_len(encoded_len, expression_len, limit)?; + } + Ok(encoded_len) + } + Self::ApplicationInputPath(path) => { + let value = value_at_projection_path(application_input, path)?; + let encoded_value = encode_canonical_cbor_v1(value).map_err(canonical_error)?; + bounded_projection_len(0, encoded_value.len(), limit) + } + } + } +} + +fn canonical_map_header_len(entry_count: usize) -> usize { + if entry_count <= 23 { + 1 + } else if u8::try_from(entry_count).is_ok() { + 2 + } else if u16::try_from(entry_count).is_ok() { + 3 + } else if u32::try_from(entry_count).is_ok() { + 5 + } else { + 9 + } +} + +fn bounded_projection_len( + current: usize, + additional: usize, + limit: usize, +) -> Result { + current + .checked_add(additional) + .filter(|encoded_len| *encoded_len <= limit) + .ok_or_else(projected_result_exceeds_bound) +} + +fn projected_result_exceeds_bound() -> EchoOperationArtifactErrorV1 { + invalid_structure("application result exceeds the compiler-declared output bound") +} + +/// Compiler-owned application-result projection plus Echo's verified target plan. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct EchoOperationApplicationResultProjectionV1 { + artifact_bytes: Vec, + artifact_identity: Hash, + operation_coordinate: String, + output_type: String, + max_output_bytes: u64, + application_input_node_key_path: Vec, + application_input_replacement_path: Vec, + runtime_expression: EchoOperationResultExpressionV1, +} + +impl EchoOperationApplicationResultProjectionV1 { + fn from_value(value: CanonicalValueV1) -> Result { + let mut fields = exact_text_map( + value, + &[ + "application_input_node_key_path", + "application_input_replacement_path", + "artifact_bytes", + "artifact_identity", + "runtime_expression", + ], + )?; + let artifact_bytes = take_bytes(&mut fields, "artifact_bytes")?; + let artifact_identity = take_hash(&mut fields, "artifact_identity")?; + let node_key_path = take_projection_path(&mut fields, "application_input_node_key_path")?; + let replacement_path = + take_projection_path(&mut fields, "application_input_replacement_path")?; + if node_key_path == replacement_path { + return Err(invalid_structure( + "result projection input bindings must be distinct", + )); + } + let mut runtime_nodes = 0; + let runtime_expression = EchoOperationResultExpressionV1::from_runtime_value( + take_field(&mut fields, "runtime_expression")?, + &mut runtime_nodes, + )?; + let (operation_coordinate, output_type, max_output_bytes, authored_expression) = + validate_edict_result_projection(&artifact_bytes, artifact_identity)?; + if !same_projection_shape(&authored_expression, &runtime_expression, &node_key_path) { + return Err(invalid_structure( + "runtime result plan does not preserve the authored projection shape", + )); + } + Ok(Self { + artifact_bytes, + artifact_identity, + operation_coordinate, + output_type, + max_output_bytes, + application_input_node_key_path: node_key_path, + application_input_replacement_path: replacement_path, + runtime_expression, + }) + } + + fn to_value(&self) -> CanonicalValueV1 { + map_value([ + ( + "application_input_node_key_path", + projection_path_value(&self.application_input_node_key_path), + ), + ( + "application_input_replacement_path", + projection_path_value(&self.application_input_replacement_path), + ), + ( + "artifact_bytes", + CanonicalValueV1::Bytes(self.artifact_bytes.clone()), + ), + ("artifact_identity", hash_value(self.artifact_identity)), + ("runtime_expression", self.runtime_expression.to_value()), + ]) + } + + /// Returns the exact compiler-owned projection identity. + #[must_use] + pub const fn artifact_identity(&self) -> Hash { + self.artifact_identity + } + + /// Returns the application result type coordinate carried by the projection. + #[must_use] + pub fn output_type(&self) -> &str { + &self.output_type + } + + fn validate_application_input_binding( + &self, + canonical_application_input_bytes: &[u8], + node: NodeKey, + replacement_bytes: &[u8], + ) -> Result<(), EchoOperationArtifactErrorV1> { + let application_input = + decode_canonical_cbor_v1(canonical_application_input_bytes).map_err(canonical_error)?; + if encode_canonical_cbor_v1(&application_input).map_err(canonical_error)? + != canonical_application_input_bytes + { + return Err(artifact_error( + EchoOperationArtifactErrorKindV1::NonCanonical, + "application input did not reproduce the exact invocation bytes", + )); + } + let CanonicalValueV1::Text(node_key) = + value_at_projection_path(&application_input, &self.application_input_node_key_path)? + else { + return Err(invalid_structure( + "application input node-key binding must resolve to text", + )); + }; + let derived_node_id: Hash = Sha256::digest(node_key.as_bytes()).into(); + if derived_node_id != node.local_id.0 { + return Err(invalid_structure( + "application input node-key binding disagrees with the invocation node", + )); + } + let CanonicalValueV1::Text(replacement) = + value_at_projection_path(&application_input, &self.application_input_replacement_path)? + else { + return Err(invalid_structure( + "application input replacement binding must resolve to text", + )); + }; + if replacement.as_bytes() != replacement_bytes { + return Err(invalid_structure( + "application input replacement binding disagrees with invocation bytes", + )); + } + Ok(()) + } + + fn evaluate( + &self, + canonical_application_input_bytes: &[u8], + ) -> Result { + let application_input = + decode_canonical_cbor_v1(canonical_application_input_bytes).map_err(canonical_error)?; + if encode_canonical_cbor_v1(&application_input).map_err(canonical_error)? + != canonical_application_input_bytes + { + return Err(artifact_error( + EchoOperationArtifactErrorKindV1::NonCanonical, + "application input did not reproduce the exact invocation bytes", + )); + } + let max_output_bytes = usize::try_from(self.max_output_bytes) + .map_err(|_| invalid_structure("application result bound is not representable"))?; + self.runtime_expression + .encoded_len_with_limit(&application_input, max_output_bytes)?; + let result = self.runtime_expression.evaluate(&application_input)?; + let canonical_result_bytes = encode_canonical_cbor_v1(&result).map_err(canonical_error)?; + let result_len = u64::try_from(canonical_result_bytes.len()) + .map_err(|_| invalid_structure("application result length is not representable"))?; + if result_len > self.max_output_bytes { + return Err(invalid_structure( + "application result exceeds the compiler-declared output bound", + )); + } + EchoOperationApplicationResultV1::new( + self.artifact_identity, + self.output_type.clone(), + canonical_result_bytes, + ) + } +} + +/// Exact canonical typed application result produced during private evaluation. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct EchoOperationApplicationResultV1 { + projection_identity: Hash, + output_type: String, + canonical_bytes: Vec, + identity: Hash, +} + +impl EchoOperationApplicationResultV1 { + fn new( + projection_identity: Hash, + output_type: String, + canonical_bytes: Vec, + ) -> Result { + validate_projection_text(&output_type)?; + let value = decode_canonical_cbor_v1(&canonical_bytes).map_err(canonical_error)?; + if encode_canonical_cbor_v1(&value).map_err(canonical_error)? != canonical_bytes { + return Err(artifact_error( + EchoOperationArtifactErrorKindV1::NonCanonical, + "application result did not reproduce the exact canonical bytes", + )); + } + let identity = + application_result_identity(projection_identity, &output_type, &canonical_bytes); + Ok(Self { + projection_identity, + output_type, + canonical_bytes, + identity, + }) + } + + fn from_value(value: CanonicalValueV1) -> Result { + let mut fields = exact_text_map( + value, + &[ + "canonical_bytes", + "identity", + "output_type", + "projection_identity", + "schema", + ], + )?; + require_text(&mut fields, "schema", APPLICATION_RESULT_SCHEMA)?; + let projection_identity = take_hash(&mut fields, "projection_identity")?; + let output_type = take_text(&mut fields, "output_type")?; + let canonical_bytes = take_bytes(&mut fields, "canonical_bytes")?; + let retained_identity = take_hash(&mut fields, "identity")?; + let result = Self::new(projection_identity, output_type, canonical_bytes)?; + if result.identity != retained_identity { + return Err(invalid_structure( + "application result identity disagrees with its exact evidence", + )); + } + Ok(result) + } + + fn to_value(&self) -> CanonicalValueV1 { + map_value([ + ( + "canonical_bytes", + CanonicalValueV1::Bytes(self.canonical_bytes.clone()), + ), + ("identity", hash_value(self.identity)), + ("output_type", text_value(&self.output_type)), + ("projection_identity", hash_value(self.projection_identity)), + ("schema", text_value(APPLICATION_RESULT_SCHEMA)), + ]) + } + + /// Returns the compiler-owned projection identity consumed by evaluation. + #[must_use] + pub const fn projection_identity(&self) -> Hash { + self.projection_identity + } + + /// Returns the Edict-authored result type coordinate. + #[must_use] + pub fn output_type(&self) -> &str { + &self.output_type + } + + /// Returns the exact canonical result bytes. + #[must_use] + pub fn canonical_bytes(&self) -> &[u8] { + &self.canonical_bytes + } + + /// Returns the domain-bound identity of the projection, type, and bytes. + #[must_use] + pub const fn identity(&self) -> Hash { + self.identity + } +} + +fn application_result_identity( + projection_identity: Hash, + output_type: &str, + canonical_bytes: &[u8], +) -> Hash { + let mut hasher = Hasher::new(); + hasher.update(APPLICATION_RESULT_ID_DOMAIN); + hasher.update(&projection_identity); + hash_len_bytes(&mut hasher, output_type.as_bytes()); + hash_len_bytes(&mut hasher, canonical_bytes); + hasher.finalize().into() +} + +fn validate_edict_result_projection( + bytes: &[u8], + expected_identity: Hash, +) -> Result<(String, String, u64, EchoOperationResultExpressionShapeV1), EchoOperationArtifactErrorV1> +{ + if bytes.len() > MAX_RESULT_PROJECTION_ARTIFACT_BYTES { + return Err(invalid_structure( + "result projection exceeds the canonical byte bound", + )); + } + let value = decode_canonical_cbor_v1(bytes).map_err(canonical_error)?; + let actual_identity = digest_canonical_value_bytes_v1(RESULT_PROJECTION_DOMAIN, &value) + .map_err(canonical_error)?; + if actual_identity != expected_identity { + return Err(invalid_structure( + "result projection bytes disagree with their identity", + )); + } + let mut fields = exact_text_map( + value, + &[ + "expression", + "maxOutputBytes", + "operationCoordinate", + "outputType", + "schema", + ], + )?; + require_text(&mut fields, "schema", RESULT_PROJECTION_SCHEMA)?; + let operation_coordinate = take_text(&mut fields, "operationCoordinate")?; + let output_type = take_text(&mut fields, "outputType")?; + validate_projection_text(&operation_coordinate)?; + validate_projection_text(&output_type)?; + let max_output_bytes = take_u64(&mut fields, "maxOutputBytes")?; + if max_output_bytes == 0 { + return Err(invalid_structure( + "result projection output bound must be positive", + )); + } + if max_output_bytes > MAX_APPLICATION_RESULT_BYTES { + return Err(invalid_structure( + "result projection output bound exceeds the runtime byte ceiling", + )); + } + let mut nodes = 0; + let expression = + parse_edict_result_projection_shape(take_field(&mut fields, "expression")?, &mut nodes)?; + if encode_canonical_cbor_v1(&decode_canonical_cbor_v1(bytes).map_err(canonical_error)?) + .map_err(canonical_error)? + != bytes + { + return Err(artifact_error( + EchoOperationArtifactErrorKindV1::NonCanonical, + "result projection did not reproduce the exact admitted bytes", + )); + } + Ok(( + operation_coordinate, + output_type, + max_output_bytes, + expression, + )) +} + +#[derive(Clone, Debug, PartialEq, Eq)] +enum EchoOperationResultExpressionShapeV1 { + Record(BTreeMap), + ApplicationInput(Vec), + CapabilityResult(Vec), +} + +fn parse_edict_result_projection_shape( + value: CanonicalValueV1, + nodes: &mut usize, +) -> Result { + *nodes = nodes + .checked_add(1) + .ok_or_else(|| invalid_structure("result projection node count overflowed"))?; + if *nodes > MAX_RESULT_PROJECTION_NODES { + return Err(invalid_structure( + "result projection exceeds the expression-node bound", + )); + } + let mut fields = text_map(value)?; + match take_text(&mut fields, "kind")?.as_str() { + "record" => { + require_field_names(&fields, &["fields"])?; + let values = text_map(take_field(&mut fields, "fields")?)?; + let mut result = BTreeMap::new(); + for (name, expression) in values { + validate_projection_text(&name)?; + result.insert( + name, + parse_edict_result_projection_shape(expression, nodes)?, + ); + } + Ok(EchoOperationResultExpressionShapeV1::Record(result)) + } + "source" => { + require_field_names(&fields, &["path", "source"])?; + let mut source = text_map(take_field(&mut fields, "source")?)?; + let source_kind = take_text(&mut source, "kind")?; + let path = take_projection_path(&mut fields, "path")?; + match source_kind.as_str() { + "applicationInput" => { + require_field_names(&source, &[])?; + Ok(EchoOperationResultExpressionShapeV1::ApplicationInput(path)) + } + "capabilityResult" => { + require_field_names(&source, &["stepId"])?; + validate_projection_text(&take_text(&mut source, "stepId")?)?; + Ok(EchoOperationResultExpressionShapeV1::CapabilityResult(path)) + } + _ => Err(invalid_structure( + "result projection contains an unsupported source", + )), + } + } + _ => Err(invalid_structure( + "result projection contains an unsupported expression", + )), + } +} + +fn same_projection_shape( + authored: &EchoOperationResultExpressionShapeV1, + runtime: &EchoOperationResultExpressionV1, + capability_result_path: &[String], +) -> bool { + match (authored, runtime) { + ( + EchoOperationResultExpressionShapeV1::Record(authored), + EchoOperationResultExpressionV1::Record(runtime), + ) => { + authored.len() == runtime.len() + && authored.iter().all(|(name, authored)| { + runtime.get(name).is_some_and(|runtime| { + same_projection_shape(authored, runtime, capability_result_path) + }) + }) + } + ( + EchoOperationResultExpressionShapeV1::ApplicationInput(authored_path), + EchoOperationResultExpressionV1::ApplicationInputPath(runtime_path), + ) => authored_path == runtime_path, + ( + EchoOperationResultExpressionShapeV1::CapabilityResult(authored_path), + EchoOperationResultExpressionV1::ApplicationInputPath(runtime_path), + ) => authored_path == capability_result_path && runtime_path == capability_result_path, + _ => false, + } +} + +fn take_projection_path( + fields: &mut BTreeMap, + name: &str, +) -> Result, EchoOperationArtifactErrorV1> { + let CanonicalValueV1::Array(values) = take_field(fields, name)? else { + return Err(invalid_structure(format!("field {name} must be an array"))); + }; + if values.len() > MAX_RESULT_PROJECTION_PATH_SEGMENTS { + return Err(invalid_structure( + "result projection path exceeds the segment bound", + )); + } + values + .into_iter() + .map(|value| { + let CanonicalValueV1::Text(value) = value else { + return Err(invalid_structure( + "result projection path segment must be text", + )); + }; + validate_projection_text(&value)?; + Ok(value) + }) + .collect() +} + +fn projection_path_value(path: &[String]) -> CanonicalValueV1 { + CanonicalValueV1::Array(path.iter().map(|segment| text_value(segment)).collect()) +} + +fn validate_projection_text(value: &str) -> Result<(), EchoOperationArtifactErrorV1> { + if value.is_empty() || value.len() > MAX_RESULT_PROJECTION_TEXT_BYTES { + return Err(invalid_structure( + "result projection text is empty or exceeds its byte bound", + )); + } + Ok(()) +} + +fn value_at_projection_path<'a>( + root: &'a CanonicalValueV1, + path: &[String], +) -> Result<&'a CanonicalValueV1, EchoOperationArtifactErrorV1> { + let mut current = root; + for segment in path { + let CanonicalValueV1::Map(entries) = current else { + return Err(invalid_structure( + "result projection path traverses a non-record value", + )); + }; + current = entries + .iter() + .find_map(|(key, value)| { + (key == &CanonicalValueV1::Text(segment.clone())).then_some(value) + }) + .ok_or_else(|| invalid_structure("result projection path is absent"))?; + } + Ok(current) +} + +fn text_map( + value: CanonicalValueV1, +) -> Result, EchoOperationArtifactErrorV1> { + let CanonicalValueV1::Map(entries) = value else { + return Err(invalid_structure("result projection node must be a map")); + }; + let mut fields = BTreeMap::new(); + for (key, value) in entries { + let CanonicalValueV1::Text(key) = key else { + return Err(invalid_structure("result projection map key must be text")); + }; + if fields.insert(key, value).is_some() { + return Err(invalid_structure("result projection repeats a map field")); + } + } + Ok(fields) +} + +fn require_field_names( + fields: &BTreeMap, + expected: &[&str], +) -> Result<(), EchoOperationArtifactErrorV1> { + let actual = fields.keys().map(String::as_str).collect::>(); + let mut expected = expected.to_vec(); + expected.sort_unstable(); + if actual != expected { + return Err(invalid_structure( + "result projection has an unexpected field set", + )); + } + Ok(()) +} + /// Exact executable-operation publication material and provenance. #[derive(Clone, Debug, PartialEq, Eq)] pub struct ExecutableOperationPackageV1 { @@ -960,6 +1655,7 @@ pub struct ExecutableOperationPackageV1 { footprint_contract_identity: Hash, budget_ceiling: EchoOperationBudgetV1, program: EchoOperationProgramV1, + application_result_projection: Option, } impl ExecutableOperationPackageV1 { @@ -999,9 +1695,50 @@ impl ExecutableOperationPackageV1 { footprint_contract_identity: profile_digest(program.footprint_contract().coordinate()), budget_ceiling, program, + application_result_projection: None, } } + /// Adds one compiler-owned application-result projection and checked target plan. + /// + /// # Errors + /// + /// Returns a structured artifact failure when either canonical artifact, + /// its identity, the bounded input paths, or the runtime expression is + /// malformed or mutually inconsistent. + #[allow(clippy::too_many_arguments)] + pub fn with_application_result_projection( + mut self, + artifact_bytes: Vec, + artifact_identity: Hash, + application_input_node_key_path: Vec, + application_input_replacement_path: Vec, + canonical_runtime_expression_bytes: &[u8], + ) -> Result { + let runtime_expression = decode_canonical_cbor_v1(canonical_runtime_expression_bytes) + .map_err(canonical_error)?; + let projection = EchoOperationApplicationResultProjectionV1::from_value(map_value([ + ( + "application_input_node_key_path", + projection_path_value(&application_input_node_key_path), + ), + ( + "application_input_replacement_path", + projection_path_value(&application_input_replacement_path), + ), + ("artifact_bytes", CanonicalValueV1::Bytes(artifact_bytes)), + ("artifact_identity", hash_value(artifact_identity)), + ("runtime_expression", runtime_expression), + ]))?; + if projection.operation_coordinate != self.operation_coordinate { + return Err(invalid_structure( + "result projection operation differs from the package operation", + )); + } + self.application_result_projection = Some(projection); + Ok(self) + } + /// Returns the public operation coordinate. #[must_use] pub fn operation_coordinate(&self) -> &str { @@ -1050,6 +1787,14 @@ impl ExecutableOperationPackageV1 { &self.program } + /// Returns the compiler-owned application-result projection when present. + #[must_use] + pub const fn application_result_projection( + &self, + ) -> Option<&EchoOperationApplicationResultProjectionV1> { + self.application_result_projection.as_ref() + } + /// Encodes exact package bytes using Edict's canonical CBOR profile. pub fn to_canonical_bytes(&self) -> Result, EchoOperationArtifactErrorV1> { if self.operation_coordinate.is_empty() { @@ -1082,7 +1827,7 @@ impl ExecutableOperationPackageV1 { } self.semantic_closure.validate()?; let program_bytes = self.program.to_canonical_bytes()?; - let value = map_value([ + let mut fields = vec![ ( "application_basis_schema_identity", hash_value(self.application_basis_schema_identity), @@ -1143,35 +1888,51 @@ impl ExecutableOperationPackageV1 { "target_profile_identity", hash_value(self.target_profile_identity), ), - ]); + ]; + if let Some(projection) = &self.application_result_projection { + fields.push(("application_result_projection", projection.to_value())); + } + let value = CanonicalValueV1::Map( + fields + .into_iter() + .map(|(key, value)| (text_value(key), value)) + .collect(), + ); encode_canonical_cbor_v1(&value).map_err(canonical_error) } fn from_canonical_bytes(bytes: &[u8]) -> Result { let value = decode_canonical_cbor_v1(bytes).map_err(canonical_error)?; - let mut fields = exact_text_map( - value, - &[ - "authority_profile_identity", - "application_basis_schema_identity", - "budget_ceiling", - "evaluation_basis_schema_identity", - "footprint_contract_identity", - "interpreter_profile_identity", - "input_schema_identity", - "intrinsic_profile_identity", - "obstruction_schema_identity", - "obstruction_interpretation_identity", - "obstruction_coordinate", - "operation_coordinate", - "program", - "result_schema_identity", - "result_interpretation_identity", - "schema", - "semantic_closure", - "target_profile_identity", - ], - )?; + let has_application_result_projection = match &value { + CanonicalValueV1::Map(entries) => entries.iter().any(|(key, _)| { + key == &CanonicalValueV1::Text("application_result_projection".to_owned()) + }), + _ => false, + }; + let mut expected_fields = vec![ + "authority_profile_identity", + "application_basis_schema_identity", + "budget_ceiling", + "evaluation_basis_schema_identity", + "footprint_contract_identity", + "interpreter_profile_identity", + "input_schema_identity", + "intrinsic_profile_identity", + "obstruction_schema_identity", + "obstruction_interpretation_identity", + "obstruction_coordinate", + "operation_coordinate", + "program", + "result_schema_identity", + "result_interpretation_identity", + "schema", + "semantic_closure", + "target_profile_identity", + ]; + if has_application_result_projection { + expected_fields.push("application_result_projection"); + } + let mut fields = exact_text_map(value, &expected_fields)?; require_text(&mut fields, "schema", PACKAGE_SCHEMA)?; let operation_coordinate = take_text(&mut fields, "operation_coordinate")?; if operation_coordinate.is_empty() { @@ -1189,6 +1950,13 @@ impl ExecutableOperationPackageV1 { } let program_bytes = take_bytes(&mut fields, "program")?; let program = EchoOperationProgramV1::from_canonical_bytes(&program_bytes)?; + let application_result_projection = if has_application_result_projection { + Some(EchoOperationApplicationResultProjectionV1::from_value( + take_field(&mut fields, "application_result_projection")?, + )?) + } else { + None + }; let package = Self { operation_coordinate, obstruction_coordinate, @@ -1225,6 +1993,7 @@ impl ExecutableOperationPackageV1 { "budget_ceiling", )?)?, program, + application_result_projection, }; package.self_validate_supported_profile()?; if package.to_canonical_bytes()? != bytes { @@ -1308,6 +2077,15 @@ impl ExecutableOperationPackageV1 { "unsupported interpreter or intrinsic profile identity", )); } + if self + .application_result_projection + .as_ref() + .is_some_and(|projection| projection.operation_coordinate != self.operation_coordinate) + { + return Err(invalid_structure( + "result projection operation differs from the package operation", + )); + } Ok(()) } } @@ -1511,6 +2289,7 @@ pub struct InstalledEchoOperationV1 { budget_ceiling: EchoOperationBudgetV1, program_id: EchoOperationProgramIdV1, program: EchoOperationProgramV1, + application_result_projection: Option, canonical_package_bytes: Vec, admission_policy_id: Hash, admission_policy: EchoOperationAdmissionPolicyV1, @@ -1551,6 +2330,14 @@ impl InstalledEchoOperationV1 { &self.program } + /// Returns the compiler-owned application-result projection when installed. + #[must_use] + pub const fn application_result_projection( + &self, + ) -> Option<&EchoOperationApplicationResultProjectionV1> { + self.application_result_projection.as_ref() + } + /// Returns the semantic identity bound by the admitted package. #[must_use] pub const fn semantic_identity(&self) -> Hash { @@ -1660,6 +2447,7 @@ pub(crate) fn installed_from_admitted( budget_ceiling: package.budget_ceiling, program_id: package.program.identity()?, program: package.program, + application_result_projection: package.application_result_projection, canonical_package_bytes: admitted.canonical_package_bytes, admission_policy_id: admitted.admission_policy_id, admission_policy: admitted.admission_policy, @@ -1999,6 +2787,7 @@ pub struct EchoOperationInvocationV1 { node: NodeKey, kind: EchoOperationInvocationKindV1, replacement_bytes: Vec, + application_input_bytes: Option>, } impl EchoOperationInvocationV1 { @@ -2026,6 +2815,7 @@ impl EchoOperationInvocationV1 { expected_value_digest, }, replacement_bytes, + application_input_bytes: None, } } @@ -2050,6 +2840,34 @@ impl EchoOperationInvocationV1 { node, kind: EchoOperationInvocationKindV1::AnchoredNodeAttachmentCreateIfAbsent, replacement_bytes, + application_input_bytes: None, + } + } + + /// Creates a projected create-if-absent invocation with exact canonical + /// application input retained for scheduler-owned result evaluation. + #[allow(clippy::too_many_arguments)] + #[must_use] + pub fn anchored_node_attachment_create_if_absent_with_application_input( + package_id: EchoOperationPackageIdV1, + operation_coordinate: impl Into, + evaluation_basis: EchoOperationEvaluationBasisV1, + authority_grant_identity: Hash, + delegated_budget: EchoOperationBudgetV1, + node: NodeKey, + replacement_bytes: Vec, + canonical_application_input_bytes: Vec, + ) -> Self { + Self { + package_id, + operation_coordinate: operation_coordinate.into(), + evaluation_basis, + authority_grant_identity, + delegated_budget, + node, + kind: EchoOperationInvocationKindV1::AnchoredNodeAttachmentCreateIfAbsent, + replacement_bytes, + application_input_bytes: Some(canonical_application_input_bytes), } } @@ -2111,11 +2929,37 @@ impl EchoOperationInvocationV1 { ) } EchoOperationInvocationKindV1::AnchoredNodeAttachmentCreateIfAbsent => { - let mut fields = Vec::from(common(CREATE_INVOCATION_SCHEMA)); + let schema = if self.application_input_bytes.is_some() { + PROJECTED_CREATE_INVOCATION_SCHEMA + } else { + CREATE_INVOCATION_SCHEMA + }; + let mut fields = Vec::from(common(schema)); fields.push(( "absence_precondition", text_value(CREATE_ABSENCE_PRECONDITION), )); + if let Some(application_input_bytes) = &self.application_input_bytes { + if application_input_bytes.len() > MAX_APPLICATION_INPUT_BYTES { + return Err(invalid_structure( + "application input exceeds the projected invocation byte ceiling", + )); + } + let application_input = decode_canonical_cbor_v1(application_input_bytes) + .map_err(canonical_error)?; + if encode_canonical_cbor_v1(&application_input).map_err(canonical_error)? + != *application_input_bytes + { + return Err(artifact_error( + EchoOperationArtifactErrorKindV1::NonCanonical, + "application input did not reproduce the exact invocation bytes", + )); + } + fields.push(( + "application_input_bytes", + CanonicalValueV1::Bytes(application_input_bytes.clone()), + )); + } CanonicalValueV1::Map( fields .into_iter() @@ -2142,7 +2986,7 @@ impl EchoOperationInvocationV1 { .ok_or_else(|| invalid_structure("invocation schema must be text"))?, _ => return Err(invalid_structure("artifact root must be a map")), }; - let (expected_fields, create_if_absent) = match schema { + let (expected_fields, create_if_absent, projected) = match schema { INVOCATION_SCHEMA => ( &[ "authority_grant_identity", @@ -2157,6 +3001,7 @@ impl EchoOperationInvocationV1 { "warp_id", ][..], false, + false, ), CREATE_INVOCATION_SCHEMA => ( &[ @@ -2172,6 +3017,24 @@ impl EchoOperationInvocationV1 { "warp_id", ][..], true, + false, + ), + PROJECTED_CREATE_INVOCATION_SCHEMA => ( + &[ + "absence_precondition", + "application_input_bytes", + "authority_grant_identity", + "delegated_budget", + "evaluation_basis", + "node_id", + "operation_coordinate", + "package_id", + "replacement_bytes", + "schema", + "warp_id", + ][..], + true, + true, ), _ => return Err(invalid_structure("unsupported invocation schema")), }; @@ -2179,7 +3042,9 @@ impl EchoOperationInvocationV1 { require_text( &mut fields, "schema", - if create_if_absent { + if projected { + PROJECTED_CREATE_INVOCATION_SCHEMA + } else if create_if_absent { CREATE_INVOCATION_SCHEMA } else { INVOCATION_SCHEMA @@ -2215,6 +3080,11 @@ impl EchoOperationInvocationV1 { }, kind, replacement_bytes: take_bytes(&mut fields, "replacement_bytes")?, + application_input_bytes: if projected { + Some(take_bytes(&mut fields, "application_input_bytes")?) + } else { + None + }, }; if invocation.operation_coordinate.is_empty() || !invocation.delegated_budget.is_nonzero() { return Err(invalid_structure( @@ -2275,6 +3145,8 @@ pub enum EchoOperationInvocationAdmissionErrorKindV1 { OperationCoordinateMismatch, /// The invocation schema does not match the installed program profile. OperationProfileMismatch, + /// Canonical application input is absent, unexpected, or rebound. + ApplicationInputMismatch, /// The runtime-owned authority profile disagrees with the package. AuthorityProfileMismatch, /// The invocation's authority grant was not admitted by runtime policy. @@ -2448,6 +3320,30 @@ fn admit_invocation_static_v1<'a>( "invocation schema differs from the installed program profile", )); } + match ( + installed.application_result_projection.as_ref(), + invocation.application_input_bytes.as_deref(), + ) { + (Some(projection), Some(application_input_bytes)) => projection + .validate_application_input_binding( + application_input_bytes, + invocation.node, + &invocation.replacement_bytes, + ) + .map_err(|error| { + invocation_admission_error( + EchoOperationInvocationAdmissionErrorKindV1::ApplicationInputMismatch, + error.to_string(), + ) + })?, + (None, None) => {} + _ => { + return Err(invocation_admission_error( + EchoOperationInvocationAdmissionErrorKindV1::ApplicationInputMismatch, + "projected packages require projected invocations and legacy packages forbid them", + )) + } + } if policy.authority_profile_identity != installed.authority_profile_identity { return Err(invocation_admission_error( EchoOperationInvocationAdmissionErrorKindV1::AuthorityProfileMismatch, @@ -2810,6 +3706,9 @@ pub enum EchoOperationObstructionKindV1 { FootprintViolation, /// The program rejected a replacement outside its bound. ReplacementTooLarge, + /// The compiler-owned result projection could not produce one bounded + /// canonical result from the exact admitted application input. + ResultProjectionInvalid, } /// Retained runtime policy evidence needed to reproduce one obstruction. @@ -3481,6 +4380,7 @@ fn obstruction_kind_from_code( 10 => Ok(EchoOperationObstructionKindV1::FootprintViolation), 11 => Ok(EchoOperationObstructionKindV1::ReplacementTooLarge), 12 => Ok(EchoOperationObstructionKindV1::EvaluationAuthorityMismatch), + 13 => Ok(EchoOperationObstructionKindV1::ResultProjectionInvalid), _ => Err(invalid_structure( "unknown executable-operation obstruction kind", )), @@ -3513,6 +4413,7 @@ pub struct PreparedEchoOperationV1 { actual_footprint_digest: Hash, consumed_budget: EchoOperationBudgetV1, patch: WarpTickPatchV1, + application_result: Option, result_id: EchoOperationResultIdV1, private_evaluation_id: EchoOperationPrivateEvaluationIdV1, preparation_id: PreparedEchoOperationIdV1, @@ -3600,6 +4501,12 @@ impl PreparedEchoOperationV1 { self.result_id } + /// Returns the exact typed application result produced by the compiler-owned projection. + #[must_use] + pub const fn application_result(&self) -> Option<&EchoOperationApplicationResultV1> { + self.application_result.as_ref() + } + pub(crate) fn prepared_patch_digest(&self) -> Hash { self.patch.digest() } @@ -3846,12 +4753,28 @@ pub(crate) fn prepare_operation_v1( required_attachment_type, &admitted.invocation.replacement_bytes, ); + let application_result = match ( + installed.application_result_projection.as_ref(), + admitted.invocation.application_input_bytes.as_deref(), + ) { + (Some(projection), Some(application_input_bytes)) => { + match projection.evaluate(application_input_bytes) { + Ok(result) => Some(result), + Err(_) => { + return obstruction(EchoOperationObstructionKindV1::ResultProjectionInvalid) + } + } + } + (None, None) => None, + _ => return obstruction(EchoOperationObstructionKindV1::ResultProjectionInvalid), + }; let result_id = operation_result_id( installed, &admitted.invocation, mode, replacement_value_digest, patch.digest(), + application_result.as_ref(), ); let private_evaluation_id = private_evaluation_id_from_parts( installed.installed_operation_id, @@ -3864,6 +4787,9 @@ pub(crate) fn prepare_operation_v1( consumed_budget, patch.digest(), result_id, + application_result + .as_ref() + .map(EchoOperationApplicationResultV1::identity), ); let preparation_id = preparation_id(private_evaluation_id, patch.digest(), result_id); EchoOperationPreparationV1::Prepared(Box::new(PreparedEchoOperationV1 { @@ -3881,6 +4807,7 @@ pub(crate) fn prepare_operation_v1( actual_footprint_digest, consumed_budget, patch, + application_result, result_id, private_evaluation_id, preparation_id, @@ -3932,8 +4859,10 @@ pub struct EchoOperationReceiptV1 { preparation_id: PreparedEchoOperationIdV1, prepared_patch_digest: Hash, prepared_result_id: EchoOperationResultIdV1, + prepared_application_result: Option, committed_patch_digest: Option, committed_result_id: Option, + committed_application_result: Option, state_root_before: Hash, state_root_after: Hash, commit_id: Hash, @@ -4065,12 +4994,24 @@ impl EchoOperationReceiptV1 { self.prepared_result_id } + /// Returns the exact typed application result produced during evaluation. + #[must_use] + pub const fn prepared_application_result(&self) -> Option<&EchoOperationApplicationResultV1> { + self.prepared_application_result.as_ref() + } + /// Returns the typed result only when it entered the committed consequence. #[must_use] pub const fn committed_result_id(&self) -> Option { self.committed_result_id } + /// Returns the exact typed application result only when it committed. + #[must_use] + pub const fn committed_application_result(&self) -> Option<&EchoOperationApplicationResultV1> { + self.committed_application_result.as_ref() + } + /// Returns the parent-visible patch digest only for a committed consequence. #[must_use] pub const fn committed_patch_digest(&self) -> Option { @@ -4150,7 +5091,7 @@ impl EchoOperationReceiptV1 { } fn to_value(&self) -> CanonicalValueV1 { - map_value([ + let mut fields = Vec::from([ ( "actual_footprint_digest", hash_value(self.actual_footprint_digest), @@ -4285,7 +5226,26 @@ impl EchoOperationReceiptV1 { "worldline_tick_after", uint_value(self.worldline_tick_after.as_u64()), ), - ]) + ]); + if let Some(prepared_application_result) = &self.prepared_application_result { + fields.push(( + "prepared_application_result", + prepared_application_result.to_value(), + )); + fields.push(( + "committed_application_result", + self.committed_application_result.as_ref().map_or( + CanonicalValueV1::Null, + EchoOperationApplicationResultV1::to_value, + ), + )); + } + CanonicalValueV1::Map( + fields + .into_iter() + .map(|(key, value)| (text_value(key), value)) + .collect(), + ) } pub(crate) fn from_canonical_bytes(bytes: &[u8]) -> Result { @@ -4303,52 +5263,61 @@ impl EchoOperationReceiptV1 { allow_composite_context: bool, ) -> Result { let value = decode_canonical_cbor_v1(bytes).map_err(canonical_error)?; - let mut fields = exact_text_map( - value, - &[ - "actual_footprint_digest", - "authority_grant_identity", - "authority_profile_identity", - "commit_global_tick", - "commit_id", - "committed_result_id", - "composition_digest", - "consumed_budget", - "declared_footprint_digest", - "delegated_budget", - "evaluation_basis", - "evaluation_basis_id", - "installed_operation_id", - "interpreter_profile_identity", - "intrinsic_profile_identity", - "invocation_admission_id", - "invocation_admission_policy_id", - "invocation_admission_maximum_budget", - "invocation_bytes_digest", - "invocation_id", - "lawpack_identity", - "operation_coordinate", - "package_admission_id", - "package_admission_policy_id", - "package_id", - "committed_patch_digest", - "prepared_patch_digest", - "prepared_result_id", - "preparation_id", - "private_evaluation_id", - "program_id", - "receipt_digest", - "schema", - "semantic_identity", - "state_root_after", - "state_root_before", - "target_profile_identity", - "terminal_posture", - "terminal_outcome_digest", - "tick_receipt_digest", - "worldline_tick_after", - ], - )?; + let has_application_result = match &value { + CanonicalValueV1::Map(entries) => entries.iter().any(|(key, _)| { + key == &CanonicalValueV1::Text("prepared_application_result".to_owned()) + || key == &CanonicalValueV1::Text("committed_application_result".to_owned()) + }), + _ => false, + }; + let mut expected_fields = vec![ + "actual_footprint_digest", + "authority_grant_identity", + "authority_profile_identity", + "commit_global_tick", + "commit_id", + "committed_result_id", + "composition_digest", + "consumed_budget", + "declared_footprint_digest", + "delegated_budget", + "evaluation_basis", + "evaluation_basis_id", + "installed_operation_id", + "interpreter_profile_identity", + "intrinsic_profile_identity", + "invocation_admission_id", + "invocation_admission_policy_id", + "invocation_admission_maximum_budget", + "invocation_bytes_digest", + "invocation_id", + "lawpack_identity", + "operation_coordinate", + "package_admission_id", + "package_admission_policy_id", + "package_id", + "committed_patch_digest", + "prepared_patch_digest", + "prepared_result_id", + "preparation_id", + "private_evaluation_id", + "program_id", + "receipt_digest", + "schema", + "semantic_identity", + "state_root_after", + "state_root_before", + "target_profile_identity", + "terminal_posture", + "terminal_outcome_digest", + "tick_receipt_digest", + "worldline_tick_after", + ]; + if has_application_result { + expected_fields.push("committed_application_result"); + expected_fields.push("prepared_application_result"); + } + let mut fields = exact_text_map(value, &expected_fields)?; require_text(&mut fields, "schema", "echo.operation-receipt/v1")?; let terminal_posture = match take_text(&mut fields, "terminal_posture")?.as_str() { "committed" => EchoOperationTerminalPostureV1::Committed, @@ -4430,6 +5399,14 @@ impl EchoOperationReceiptV1 { &mut fields, "prepared_result_id", )?), + prepared_application_result: if has_application_result { + Some(EchoOperationApplicationResultV1::from_value(take_field( + &mut fields, + "prepared_application_result", + )?)?) + } else { + None + }, committed_patch_digest: match take_field(&mut fields, "committed_patch_digest")? { CanonicalValueV1::Null => None, CanonicalValueV1::Bytes(bytes) => Some(bytes.try_into().map_err(|_| { @@ -4443,6 +5420,14 @@ impl EchoOperationReceiptV1 { }, committed_result_id: take_optional_hash(&mut fields, "committed_result_id")? .map(EchoOperationResultIdV1), + committed_application_result: if has_application_result { + match take_field(&mut fields, "committed_application_result")? { + CanonicalValueV1::Null => None, + value => Some(EchoOperationApplicationResultV1::from_value(value)?), + } + } else { + None + }, state_root_before: take_hash(&mut fields, "state_root_before")?, state_root_after: take_hash(&mut fields, "state_root_after")?, commit_id: take_hash(&mut fields, "commit_id")?, @@ -4518,6 +5503,10 @@ impl EchoOperationReceiptV1 { receipt.consumed_budget, receipt.prepared_patch_digest, receipt.prepared_result_id, + receipt + .prepared_application_result + .as_ref() + .map(EchoOperationApplicationResultV1::identity), ) != receipt.private_evaluation_id { return Err(invalid_structure( @@ -4566,6 +5555,8 @@ impl EchoOperationReceiptV1 { || receipt.tick_receipt_digest == [0; 32] || receipt.committed_patch_digest.is_none() || receipt.committed_result_id != Some(receipt.prepared_result_id) + || receipt.committed_application_result + != receipt.prepared_application_result || receipt.composition_digest.is_none() || (receipt.committed_patch_digest != Some(receipt.prepared_patch_digest) && !allow_composite_context) @@ -4586,6 +5577,7 @@ impl EchoOperationReceiptV1 { || receipt.tick_receipt_digest != [0; 32] || receipt.committed_patch_digest.is_some() || receipt.committed_result_id.is_some() + || receipt.committed_application_result.is_some() || receipt.composition_digest.is_some() || receipt.state_root_before != receipt.state_root_after => { @@ -4696,10 +5688,24 @@ pub(crate) fn validate_receipt_installation_v1( && receipt .consumed_budget .fits_within(receipt.delegated_budget); + let application_result_matches = match ( + installed.application_result_projection.as_ref(), + receipt.prepared_application_result.as_ref(), + ) { + (None, None) => true, + (Some(projection), Some(result)) => { + let expected_projection_identity = projection.artifact_identity(); + let retained_projection_identity = result.projection_identity(); + retained_projection_identity == expected_projection_identity + && result.output_type() == projection.output_type() + } + _ => false, + }; if !package_evidence_matches || !package_policy_matches || !semantic_evidence_matches || !resource_evidence_matches + || !application_result_matches { return Err(invalid_structure( "operation receipt does not match its retained installation", @@ -4708,6 +5714,31 @@ pub(crate) fn validate_receipt_installation_v1( Ok(()) } +pub(crate) fn validate_receipt_application_result_v1( + receipt: &EchoOperationReceiptV1, + installed: &InstalledEchoOperationV1, + canonical_invocation_bytes: &[u8], +) -> Result<(), EchoOperationArtifactErrorV1> { + let invocation = EchoOperationInvocationV1::from_canonical_bytes(canonical_invocation_bytes)?; + let result_matches = match ( + installed.application_result_projection.as_ref(), + receipt.prepared_application_result.as_ref(), + invocation.application_input_bytes.as_deref(), + ) { + (None, None, None) => true, + (Some(projection), Some(retained_result), Some(application_input_bytes)) => projection + .evaluate(application_input_bytes) + .is_ok_and(|expected_result| expected_result == *retained_result), + _ => false, + }; + if !result_matches { + return Err(invalid_structure( + "operation receipt result does not reproduce from the retained invocation", + )); + } + Ok(()) +} + /// Failure while turning one complete private preparation into commit material. #[derive(Clone, Copy, Debug, Error, PartialEq, Eq)] pub enum EchoOperationCommitErrorV1 { @@ -5397,8 +6428,12 @@ fn build_receipt( preparation_id: prepared.preparation_id, prepared_patch_digest: prepared.patch.digest(), prepared_result_id: prepared.result_id, + prepared_application_result: prepared.application_result.clone(), committed_patch_digest: committed.then(|| prepared.patch.digest()), committed_result_id: committed.then_some(prepared.result_id), + committed_application_result: committed + .then(|| prepared.application_result.clone()) + .flatten(), state_root_before: terminal.state_root_before, state_root_after: terminal.state_root_after, commit_id: terminal.commit_id, @@ -5445,6 +6480,7 @@ fn receipt_digest(receipt: &EchoOperationReceiptV1) -> Hash { hasher.update(&receipt.preparation_id.as_hash()); hasher.update(&receipt.prepared_patch_digest); hasher.update(&receipt.prepared_result_id.as_hash()); + hash_optional_application_result(&mut hasher, receipt.prepared_application_result.as_ref()); match receipt.committed_patch_digest { None => { hasher.update(&[0]); @@ -5460,6 +6496,7 @@ fn receipt_digest(receipt: &EchoOperationReceiptV1) -> Hash { .committed_result_id .map(EchoOperationResultIdV1::as_hash), ); + hash_optional_application_result(&mut hasher, receipt.committed_application_result.as_ref()); hasher.update(&receipt.state_root_before); hasher.update(&receipt.state_root_after); hasher.update(&receipt.commit_id); @@ -5486,6 +6523,7 @@ fn terminal_outcome_digest(receipt: &EchoOperationReceiptV1) -> Hash { hasher.update(&receipt.preparation_id.as_hash()); hasher.update(&receipt.prepared_patch_digest); hasher.update(&receipt.prepared_result_id.as_hash()); + hash_optional_application_result(&mut hasher, receipt.prepared_application_result.as_ref()); hasher.update(&[terminal_posture_code(receipt.terminal_posture)]); hash_optional_id(&mut hasher, receipt.committed_patch_digest); hash_optional_id( @@ -5494,6 +6532,7 @@ fn terminal_outcome_digest(receipt: &EchoOperationReceiptV1) -> Hash { .committed_result_id .map(EchoOperationResultIdV1::as_hash), ); + hash_optional_application_result(&mut hasher, receipt.committed_application_result.as_ref()); hash_optional_id(&mut hasher, receipt.composition_digest); hasher.update(&receipt.state_root_before); hasher.update(&receipt.state_root_after); @@ -5522,6 +6561,22 @@ fn hash_optional_id(hasher: &mut Hasher, value: Option) { } } +fn hash_optional_application_result( + hasher: &mut Hasher, + result: Option<&EchoOperationApplicationResultV1>, +) { + match result { + None => { + hasher.update(&[0]); + } + Some(result) => { + hasher.update(&[1]); + hasher.update(&result.identity); + hash_len_bytes(hasher, &result.canonical_bytes); + } + } +} + fn singleton_composition_digest(prepared: &PreparedEchoOperationV1) -> Hash { singleton_composition_digest_from_parts( prepared.preparation_id, @@ -5614,6 +6669,7 @@ fn operation_result_id( mode: AnchoredNodeOperationModeV1, replacement_value_digest: Hash, patch_digest: Hash, + application_result: Option<&EchoOperationApplicationResultV1>, ) -> EchoOperationResultIdV1 { let mut hasher = Hasher::new(); match mode { @@ -5630,7 +6686,11 @@ fn operation_result_id( hasher.update(&expected_value_digest); } AnchoredNodeOperationModeV1::CreateIfAbsent => { - hasher.update(CREATE_RESULT_ID_DOMAIN); + hasher.update(if application_result.is_some() { + PROJECTED_CREATE_RESULT_ID_DOMAIN + } else { + CREATE_RESULT_ID_DOMAIN + }); hasher.update(&installed.installed_operation_id.as_hash()); hasher.update(&profile_digest(CREATE_RESULT_SCHEMA)); hasher.update(invocation.node.warp_id.as_bytes()); @@ -5640,6 +6700,9 @@ fn operation_result_id( } hasher.update(&replacement_value_digest); hasher.update(&patch_digest); + if let Some(application_result) = application_result { + hasher.update(&application_result.identity); + } EchoOperationResultIdV1(hasher.finalize().into()) } @@ -5655,6 +6718,7 @@ fn private_evaluation_id_from_parts( consumed_budget: EchoOperationBudgetV1, patch_digest: Hash, result_id: EchoOperationResultIdV1, + application_result_identity: Option, ) -> EchoOperationPrivateEvaluationIdV1 { let mut hasher = Hasher::new(); hasher.update(PRIVATE_EVALUATION_ID_DOMAIN); @@ -5668,6 +6732,10 @@ fn private_evaluation_id_from_parts( hash_budget(&mut hasher, consumed_budget); hasher.update(&patch_digest); hasher.update(&result_id.as_hash()); + if let Some(application_result_identity) = application_result_identity { + hasher.update(&[1]); + hasher.update(&application_result_identity); + } EchoOperationPrivateEvaluationIdV1(hasher.finalize().into()) } @@ -5698,6 +6766,7 @@ fn obstruction_kind_code(kind: EchoOperationObstructionKindV1) -> u8 { EchoOperationObstructionKindV1::FootprintViolation => 10, EchoOperationObstructionKindV1::ReplacementTooLarge => 11, EchoOperationObstructionKindV1::EvaluationAuthorityMismatch => 12, + EchoOperationObstructionKindV1::ResultProjectionInvalid => 13, } } @@ -6151,6 +7220,554 @@ mod tests { } } + fn result_source(kind: &str, step_id: Option<&str>, path: &[&str]) -> CanonicalValueV1 { + let source = match step_id { + Some(step_id) => { + map_value([("kind", text_value(kind)), ("stepId", text_value(step_id))]) + } + None => map_value([("kind", text_value(kind))]), + }; + map_value([ + ("kind", text_value("source")), + ( + "path", + CanonicalValueV1::Array(path.iter().map(|value| text_value(value)).collect()), + ), + ("source", source), + ]) + } + + fn projection_test_package(operation_coordinate: &str) -> ExecutableOperationPackageV1 { + ExecutableOperationPackageV1::new( + operation_coordinate, + "echo.fixture.ProjectionBinding.Obstruction/v1", + EchoOperationSemanticClosureV1::new( + digest(171), + digest(172), + digest(173), + digest(174), + "echo.fixture.ProjectionBindingSchema.v1", + digest(175), + "echo.fixture.ProjectionBindingLawpack.v1", + digest(176), + ), + echo_operation_create_if_absent_target_profile_identity_v1(), + digest(177), + EchoOperationBudgetV1::new(8, 1_024, 1_024), + EchoOperationProgramV1::anchored_node_attachment_create_if_absent( + crate::make_type_id("projection-binding-node"), + crate::make_type_id("projection-binding-atom"), + 1_024, + ), + ) + } + + #[test] + fn runtime_projection_cannot_rebind_authored_source_kind_or_path() { + let operation_coordinate = "echo.fixture.ProjectionBinding.v1"; + let cases = [ + ( + result_source("applicationInput", None, &["message"]), + result_source("applicationInput", None, &["key"]), + ), + ( + result_source("capabilityResult", Some("create"), &["key"]), + result_source("applicationInput", None, &["message"]), + ), + ]; + + for (authored_expression, runtime_expression) in cases { + let projection_value = map_value([ + ("expression", authored_expression), + ("maxOutputBytes", uint_value(1_024)), + ("operationCoordinate", text_value(operation_coordinate)), + ( + "outputType", + text_value("echo.fixture.ProjectionBindingResult/v1"), + ), + ("schema", text_value(RESULT_PROJECTION_SCHEMA)), + ]); + let projection_bytes = + encode_canonical_cbor_v1(&projection_value).expect("projection encodes"); + let projection_identity = + digest_canonical_value_bytes_v1(RESULT_PROJECTION_DOMAIN, &projection_value) + .expect("projection identity computes"); + let runtime_expression_bytes = + encode_canonical_cbor_v1(&runtime_expression).expect("runtime expression encodes"); + + let error = projection_test_package(operation_coordinate) + .with_application_result_projection( + projection_bytes, + projection_identity, + vec!["key".to_owned()], + vec!["message".to_owned()], + &runtime_expression_bytes, + ) + .expect_err("runtime projection cannot rebind an authored source"); + assert_eq!( + error.detail(), + "runtime result plan does not preserve the authored projection shape", + ); + } + } + + fn projected_create_fixture( + max_output_bytes: u64, + ) -> ( + InstalledEchoOperationV1, + WorldlineState, + EchoOperationEvaluationBasisV1, + EchoOperationInvocationAdmissionPolicyV1, + EchoOperationInvocationV1, + Vec, + ) { + let operation_coordinate = "echo.fixture.ProjectedCreate.v1"; + let output_type = "echo.fixture.ProjectedCreated/v1"; + let authored_expression = map_value([ + ( + "fields", + map_value([ + ( + "address", + result_source("capabilityResult", Some("create"), &["key"]), + ), + ( + "body", + result_source("applicationInput", None, &["message"]), + ), + ]), + ), + ("kind", text_value("record")), + ]); + let projection_value = map_value([ + ("expression", authored_expression), + ("maxOutputBytes", uint_value(max_output_bytes)), + ("operationCoordinate", text_value(operation_coordinate)), + ("outputType", text_value(output_type)), + ("schema", text_value(RESULT_PROJECTION_SCHEMA)), + ]); + let projection_bytes = + encode_canonical_cbor_v1(&projection_value).expect("projection encodes"); + let projection_identity = + digest_canonical_value_bytes_v1(RESULT_PROJECTION_DOMAIN, &projection_value) + .expect("projection identity computes"); + let runtime_expression = map_value([ + ( + "fields", + map_value([ + ("address", result_source("applicationInput", None, &["key"])), + ( + "body", + result_source("applicationInput", None, &["message"]), + ), + ]), + ), + ("kind", text_value("record")), + ]); + let runtime_expression_bytes = + encode_canonical_cbor_v1(&runtime_expression).expect("runtime expression encodes"); + let authority_profile = digest(201); + let package = ExecutableOperationPackageV1::new( + operation_coordinate, + "echo.fixture.ProjectedCreate.Obstruction/v1", + EchoOperationSemanticClosureV1::new( + digest(202), + digest(203), + digest(204), + digest(205), + "echo.fixture.ProjectedCreateSchema.v1", + digest(206), + "echo.fixture.ProjectedCreateLawpack.v1", + digest(207), + ), + echo_operation_create_if_absent_target_profile_identity_v1(), + authority_profile, + EchoOperationBudgetV1::new(8, 1_024, 1_024), + EchoOperationProgramV1::anchored_node_attachment_create_if_absent( + crate::make_type_id("projected-created-node"), + crate::make_type_id("projected-created-atom"), + 1_024, + ), + ) + .with_application_result_projection( + projection_bytes, + projection_identity, + vec!["key".to_owned()], + vec!["message".to_owned()], + &runtime_expression_bytes, + ) + .expect("projection attaches"); + let package_bytes = package.to_canonical_bytes().expect("package encodes"); + let package_id = echo_operation_package_id_v1(&package_bytes); + let installed = installed_from_admitted( + admit_package_v1( + &EchoOperationAdmissionPolicyV1::exact( + package_id, + operation_coordinate, + authority_profile, + EchoOperationBudgetV1::new(8, 1_024, 1_024), + ), + package_bytes, + ) + .expect("package admits"), + ) + .expect("package installs"); + + let warp_id = crate::make_warp_id("projected-create-warp"); + let root_node = crate::make_node_id("projected-create-root"); + let mut store = crate::GraphStore::new(warp_id); + store.insert_node( + root_node, + NodeRecord { + ty: crate::make_type_id("projected-create-root-type"), + }, + ); + let mut warp_state = crate::WarpState::new(); + warp_state.upsert_instance( + crate::WarpInstance { + warp_id, + root_node, + parent: None, + }, + store, + ); + let state = WorldlineState::new( + warp_state, + NodeKey { + warp_id, + local_id: root_node, + }, + ) + .expect("fixture state is lawful"); + let key = "fixture-key"; + let node = NodeKey { + warp_id, + local_id: crate::NodeId(Sha256::digest(key.as_bytes()).into()), + }; + let application_input = map_value([ + ("key", text_value(key)), + ("message", text_value("fixture-message")), + ]); + let application_input_bytes = + encode_canonical_cbor_v1(&application_input).expect("application input encodes"); + let basis = EchoOperationEvaluationBasisV1::new( + WriterHeadKey { + worldline_id: crate::WorldlineId::from_bytes(digest(208)), + head_id: crate::HeadId::from_bytes(digest(209)), + }, + WorldlineTick::ZERO, + None, + state.state_root(), + digest(210), + echo_operation_anchored_node_absent_application_basis_v1(node), + ); + let authority_grant = digest(211); + let invocation = + EchoOperationInvocationV1::anchored_node_attachment_create_if_absent_with_application_input( + package_id, + operation_coordinate, + basis, + authority_grant, + EchoOperationBudgetV1::new(3, 64, 79), + node, + b"fixture-message".to_vec(), + application_input_bytes.clone(), + ); + let policy = EchoOperationInvocationAdmissionPolicyV1::new( + authority_profile, + authority_grant, + EchoOperationBudgetV1::new(8, 1_024, 1_024), + ); + ( + installed, + state, + basis, + policy, + invocation, + application_input_bytes, + ) + } + + #[test] + fn projected_invocation_rejects_missing_or_rebound_application_input() { + let (installed, state, basis, policy, invocation, _) = projected_create_fixture(1_024); + let legacy = EchoOperationInvocationV1::anchored_node_attachment_create_if_absent( + invocation.package_id, + invocation.operation_coordinate.clone(), + basis, + invocation.authority_grant_identity, + invocation.delegated_budget, + invocation.node, + invocation.replacement_bytes.clone(), + ); + let authority = EchoOperationEvaluationAuthorityV1::new(); + let error = admit_invocation_v1( + Some(&installed), + policy, + &legacy + .to_canonical_bytes() + .expect("legacy invocation encodes"), + basis, + &state, + authority.clone(), + ) + .expect_err("a projected package must reject an invocation without application input"); + assert_eq!( + error.kind(), + EchoOperationInvocationAdmissionErrorKindV1::ApplicationInputMismatch + ); + + let rebound_input = encode_canonical_cbor_v1(&map_value([ + ("key", text_value("another-key")), + ("message", text_value("fixture-message")), + ])) + .expect("rebound input encodes"); + let rebound = + EchoOperationInvocationV1::anchored_node_attachment_create_if_absent_with_application_input( + invocation.package_id, + invocation.operation_coordinate, + basis, + invocation.authority_grant_identity, + invocation.delegated_budget, + invocation.node, + invocation.replacement_bytes, + rebound_input, + ); + let error = admit_invocation_v1( + Some(&installed), + policy, + &rebound + .to_canonical_bytes() + .expect("rebound invocation encodes"), + basis, + &state, + authority, + ) + .expect_err("application input cannot retarget the graph consequence"); + assert_eq!( + error.kind(), + EchoOperationInvocationAdmissionErrorKindV1::ApplicationInputMismatch + ); + } + + #[test] + fn projected_package_rejects_an_unbounded_result_declaration() { + let operation_coordinate = "echo.fixture.UnboundedProjectedCreate.v1"; + let projection = map_value([ + ( + "expression", + result_source("applicationInput", None, &["message"]), + ), + ("maxOutputBytes", uint_value(65_537)), + ("operationCoordinate", text_value(operation_coordinate)), + ( + "outputType", + text_value("echo.fixture.UnboundedProjectedCreated/v1"), + ), + ("schema", text_value(RESULT_PROJECTION_SCHEMA)), + ]); + let projection_bytes = encode_canonical_cbor_v1(&projection).expect("projection encodes"); + let projection_identity = + digest_canonical_value_bytes_v1(RESULT_PROJECTION_DOMAIN, &projection) + .expect("projection identity computes"); + + let error = validate_edict_result_projection(&projection_bytes, projection_identity) + .expect_err("runtime admission must cap the compiler-declared result size"); + + assert!( + error + .to_string() + .contains("result projection output bound exceeds"), + "unexpected refusal: {error}" + ); + } + + #[test] + fn projected_invocation_rejects_oversized_canonical_application_input() { + let (_, _, _, _, mut invocation, _) = projected_create_fixture(1_024); + invocation.application_input_bytes = Some( + encode_canonical_cbor_v1(&map_value([ + ("key", text_value("fixture-key")), + ("message", text_value(&"x".repeat(65_537))), + ])) + .expect("oversized application input remains canonical"), + ); + + let error = invocation + .to_canonical_bytes() + .expect_err("projected invocation input must have a fixed byte ceiling"); + + assert!( + error.to_string().contains("application input exceeds"), + "unexpected refusal: {error}" + ); + } + + #[test] + fn projected_result_size_preflight_rejects_repeated_large_input() { + let expression = EchoOperationResultExpressionV1::Record( + (0..MAX_RESULT_PROJECTION_NODES - 1) + .map(|index| { + ( + format!("field-{index:03}"), + EchoOperationResultExpressionV1::ApplicationInputPath(vec![ + "message".to_owned() + ]), + ) + }) + .collect(), + ); + let application_input = map_value([("message", text_value(&"x".repeat(32_768)))]); + + let error = expression + .encoded_len_with_limit( + &application_input, + usize::try_from(MAX_APPLICATION_RESULT_BYTES) + .expect("runtime result ceiling fits in usize"), + ) + .expect_err("projection expansion must fail before constructing the result value"); + + assert!( + error + .to_string() + .contains("application result exceeds the compiler-declared output bound"), + "unexpected refusal: {error}" + ); + } + + #[test] + fn optional_application_result_hashes_explicit_absence() { + let mut actual = Hasher::new(); + hash_optional_application_result(&mut actual, None); + let mut expected = Hasher::new(); + expected.update(&[0]); + + assert_eq!(actual.finalize(), expected.finalize()); + } + + #[test] + fn scheduler_evaluation_commits_and_recovers_exact_projected_result() { + let (installed, mut state, basis, policy, invocation, _) = projected_create_fixture(1_024); + let invocation_bytes = invocation.to_canonical_bytes().expect("invocation encodes"); + let authority = EchoOperationEvaluationAuthorityV1::new(); + let admitted = admit_invocation_v1( + Some(&installed), + policy, + &invocation_bytes, + basis, + &state, + authority.clone(), + ) + .expect("projected invocation admits"); + let EchoOperationPreparationV1::Prepared(prepared) = prepare_operation_v1( + Some(&installed), + admitted, + basis, + &state, + crate::POLICY_ID_NO_POLICY_V0, + &authority, + ) else { + panic!("projected invocation prepares"); + }; + let expected_bytes = encode_canonical_cbor_v1(&map_value([ + ("address", text_value("fixture-key")), + ("body", text_value("fixture-message")), + ])) + .expect("expected result encodes"); + let prepared_result = prepared + .application_result() + .expect("private evaluation produces an application result"); + assert_eq!(prepared_result.canonical_bytes(), expected_bytes); + assert_eq!( + prepared_result.output_type(), + "echo.fixture.ProjectedCreated/v1" + ); + + let committed = commit_prepared_to_state(&prepared, &mut state, GlobalTick::from_raw(1)) + .expect("projected consequence commits"); + let receipt = committed.evidence.receipt(); + assert_eq!( + receipt + .committed_application_result() + .expect("receipt carries committed application result") + .canonical_bytes(), + expected_bytes + ); + let retained = retain_committed_execution_v1(&committed.evidence) + .expect("committed result retains for WAL"); + let recovered = recover_committed_execution_receipt_v1(&retained) + .expect("committed result recovers from WAL evidence"); + assert_eq!( + recovered + .committed_application_result() + .expect("recovery preserves the application result") + .canonical_bytes(), + expected_bytes + ); + validate_receipt_installation_v1(&recovered, &installed) + .expect("recovered result remains bound to the installed projection"); + validate_receipt_application_result_v1(&recovered, &installed, &invocation_bytes) + .expect("recovered result reproduces from the retained invocation"); + + let mut substituted = recovered; + let retained_result = substituted + .prepared_application_result + .as_ref() + .expect("fixture has a projected result"); + let substituted_bytes = encode_canonical_cbor_v1(&map_value([ + ("address", text_value("fixture-key")), + ("body", text_value("substituted-message")), + ])) + .expect("substituted result encodes"); + let substituted_result = EchoOperationApplicationResultV1::new( + retained_result.projection_identity, + retained_result.output_type.clone(), + substituted_bytes, + ) + .expect("substituted result remains canonical"); + substituted.prepared_application_result = Some(substituted_result.clone()); + substituted.committed_application_result = Some(substituted_result); + validate_receipt_application_result_v1(&substituted, &installed, &invocation_bytes) + .expect_err("substituted result bytes must not reproduce from the invocation"); + substituted.terminal_outcome_digest = terminal_outcome_digest(&substituted); + substituted.receipt_digest = receipt_digest(&substituted); + recover_committed_execution_receipt_v1( + &substituted + .to_canonical_bytes() + .expect("coordinated substitution encodes"), + ) + .expect_err("result-byte substitution must break private-evaluation evidence"); + } + + #[test] + fn projected_result_bound_fails_closed_without_a_patch() { + let (installed, state, basis, policy, invocation, _) = projected_create_fixture(1); + let authority = EchoOperationEvaluationAuthorityV1::new(); + let admitted = admit_invocation_v1( + Some(&installed), + policy, + &invocation.to_canonical_bytes().expect("invocation encodes"), + basis, + &state, + authority.clone(), + ) + .expect("bounded invocation admits before evaluation"); + let EchoOperationPreparationV1::Obstructed(obstruction) = prepare_operation_v1( + Some(&installed), + admitted, + basis, + &state, + crate::POLICY_ID_NO_POLICY_V0, + &authority, + ) else { + panic!("an oversized application result must not produce a patch"); + }; + assert_eq!( + obstruction.kind(), + EchoOperationObstructionKindV1::ResultProjectionInvalid + ); + } + #[cfg(debug_assertions)] #[test] #[should_panic(expected = "Action member index is the Tick receipt entry index")] @@ -6739,6 +8356,7 @@ mod tests { consumed_budget, prepared_patch_digest, prepared_result_id, + None, ); let prepared_id = preparation_id( private_evaluation_id, @@ -6781,8 +8399,10 @@ mod tests { preparation_id: prepared_id, prepared_patch_digest, prepared_result_id, + prepared_application_result: None, committed_patch_digest: Some(prepared_patch_digest), committed_result_id: Some(prepared_result_id), + committed_application_result: None, state_root_before: basis.state_root, state_root_after: digest(24), commit_id: digest(25), @@ -6882,6 +8502,7 @@ mod tests { below_program_minimum.consumed_budget, below_program_minimum.prepared_patch_digest, below_program_minimum.prepared_result_id, + None, ); below_program_minimum.preparation_id = preparation_id( below_program_minimum.private_evaluation_id, @@ -6981,6 +8602,7 @@ mod tests { }, replacement_value_digest, patch_digest, + None, ), expected_some, "compare-and-set must hash identically to the legacy untagged digest layout" diff --git a/crates/warp-core/src/lib.rs b/crates/warp-core/src/lib.rs index e3e058e8..4b79ff44 100644 --- a/crates/warp-core/src/lib.rs +++ b/crates/warp-core/src/lib.rs @@ -244,9 +244,9 @@ pub use echo_operation::{ AdmittedExecutableOperationPackageV1, EchoOperationActionDecisionCoordinateV1, EchoOperationActionOutcomeV1, EchoOperationAdmissionErrorKindV1, EchoOperationAdmissionErrorV1, EchoOperationAdmissionPolicyV1, EchoOperationAnchoredNodeOccupancyV1, - EchoOperationApplicationBasisV1, EchoOperationArtifactErrorKindV1, - EchoOperationArtifactErrorV1, EchoOperationBudgetV1, EchoOperationCommitErrorV1, - EchoOperationEvaluationBasisIdV1, EchoOperationEvaluationBasisV1, + EchoOperationApplicationBasisV1, EchoOperationApplicationResultV1, + EchoOperationArtifactErrorKindV1, EchoOperationArtifactErrorV1, EchoOperationBudgetV1, + EchoOperationCommitErrorV1, EchoOperationEvaluationBasisIdV1, EchoOperationEvaluationBasisV1, EchoOperationExecutionEvidenceV1, EchoOperationFootprintConflictV1, EchoOperationFootprintContractV1, EchoOperationInstallationErrorKindV1, EchoOperationInstallationErrorV1, EchoOperationInvocationAdmissionErrorKindV1, diff --git a/crates/warp-core/src/trusted_runtime_host.rs b/crates/warp-core/src/trusted_runtime_host.rs index 235d0160..0f7c4471 100644 --- a/crates/warp-core/src/trusted_runtime_host.rs +++ b/crates/warp-core/src/trusted_runtime_host.rs @@ -52,8 +52,8 @@ use crate::{ reconstruct_action_evaluation_v1, reconstruct_action_preparation_v1, recover_action_outcome_v1, recover_committed_execution_receipt_v1, recover_installation_v1, retain_action_outcome_v1, retain_committed_execution_v1, retain_installation_v1, - validate_receipt_installation_v1, EchoOperationEvaluationAuthorityV1, - SchedulerEchoOperationCandidateV1, + validate_receipt_application_result_v1, validate_receipt_installation_v1, + EchoOperationEvaluationAuthorityV1, SchedulerEchoOperationCandidateV1, }, provider_contract::admit_provider_contract_package_v1, AdmittedEchoOperationInvocationV1, AdmittedExecutableOperationPackageV1, @@ -5111,6 +5111,8 @@ fn validate_recovered_echo_operation_action_outcomes( match outcome { EchoOperationActionOutcomeV1::Committed(receipt) => { if validate_receipt_installation_v1(receipt, installed).is_err() + || validate_receipt_application_result_v1(receipt, installed, invocation_bytes) + .is_err() || receipt.tick_receipt_digest() != correlation.tick_receipt_digest || receipt.commit_id() != correlation.commit_hash || receipt.commit_global_tick() != Some(correlation.commit_global_tick) diff --git a/docs/adr/0025-scheduler-owned-executable-operation-actions.md b/docs/adr/0025-scheduler-owned-executable-operation-actions.md index 63244353..d80996c2 100644 --- a/docs/adr/0025-scheduler-owned-executable-operation-actions.md +++ b/docs/adr/0025-scheduler-owned-executable-operation-actions.md @@ -114,6 +114,41 @@ informal statement that composed preparations share identical complete basis bytes: they share the runtime parent fields, while the separately typed application proposition remains candidate-specific. +### Compiler-owned typed results are evaluation evidence + +An executable-operation package may bind one exact compiler-emitted +application-result projection. The projected invocation retains the exact +canonical application input required by that projection. Echo validates both +bindings during admission, but it does not author the result schema or +reconstruct application meaning in native code. + +The v1 admission profile caps the retained canonical application input at +65,536 bytes and the compiler-declared maximum result size at 65,536 bytes. +These fixed ceilings apply before scheduler evaluation: both independent +provider components reject a declared result ceiling above Echo's runtime +maximum. Runtime evaluation then computes the produced canonical output length +against that admitted bound before it clones or assembles the projected value. +The projection artifact, expression-node count, path depth, and text segments +retain their separate structural bounds. Configuration-derived node-key and +replacement field names become projection path segments and must satisfy the +same 1,024-byte text bound before package construction. + +During private Tick construction, the scheduler evaluates the installed +projection over that admitted input. A successful applied Action retains: + +- the projection artifact identity; +- the compiler-declared output type coordinate; +- the exact canonical result bytes; and +- a domain-separated result identity over those propositions. + +The same evidence is carried by the typed Action outcome, committed Receipt, +and scheduler WAL transaction. Recovery re-evaluates the installed projection +over the exact application input retained by the original invocation and +requires byte-for-byte equality with the retained typed result before +publishing the recovered outcome or Receipt. An obstruction carries no +application result and no state mutation. Replay consumes the retained bytes; +no native callback or application-specific result reconstruction participates. + ### Tick construction is atomic Prepared candidates are considered in canonical Action order. The scheduler @@ -171,6 +206,8 @@ and receipt correlation. methods until issue #689 removes that exception. - Two independent executable-operation Actions can contribute to one scheduler-owned Tick. +- A successful projected Action exposes the compiler-declared result as exact + canonical bytes in its outcome, Receipt, WAL, and recovery evidence. - A typed obstruction is durable evidence and cannot hide a state mutation. - Filesystem durability no longer depends on several scheduler transactions being atomically appended as an external batch. @@ -192,14 +229,19 @@ The implementation is accepted only with executable witnesses that prove: 7. Typed obstruction contributes no operations. 8. The decided Tick is durable before frontier and receipt publication. 9. Fresh-host recovery reconstructs Action outcomes, Tick, state, and receipts. -10. Direct prepare/commit is marked transitional and absent from the +10. A compiler-owned result projection produces exact typed canonical bytes + during scheduler evaluation, and fresh-host recovery reproduces those + bytes and their identity. +11. Rebound projection artifacts, application inputs, result bytes, or result + identities fail closed before publication. +12. Direct prepare/commit is marked transitional and absent from the application-facing surface. -11. Removal of the remaining public host-owner compatibility seams is tracked +13. Removal of the remaining public host-owner compatibility seams is tracked separately rather than claimed complete by this decision. ## Non-Goals -- Real Edict compiler emission or a production Graft lawpack. +- A production Graft lawpack. - Provider-v1 or native callback generalization. - Arbitrary multi-record program semantics. - Cross-head or cross-worldline atomic Ticks. diff --git a/docs/architecture/application-contract-hosting.md b/docs/architecture/application-contract-hosting.md index 08d196f8..83374dcb 100644 --- a/docs/architecture/application-contract-hosting.md +++ b/docs/architecture/application-contract-hosting.md @@ -167,16 +167,16 @@ The slice exposes no application matcher, executor, or footprint callback. A generic provider lowerer now emits the package from exact Edict source, Core, lawpack, exports, adapter, target-configuration, and Target IR artifacts, and a structurally separate provider verifier independently reconstructs that -relation. Edict's public application-build command does not yet assemble those -inputs end to end, and the slice does not implement Jedit `ReplaceRange`, any -Graft operation, or cross-head atomic filesystem-WAL persistence. Provider v1 -remains stable while consumers migrate; it is not renamed or silently -reinterpreted as the executable-operation corridor. The program digest supplies -executable meaning only: it cannot independently confer an operation -coordinate, invocability, or authority, and Echo cannot install or invoke it -naked. The admitted operation package binds the public contract and semantic -closure to the exact program, after which Echo independently admits each -invocation. +relation. Edict's public application-build command assembles those inputs end +to end and invokes the checked Echo lowerer and structurally separate +verifier. The slice does not implement Jedit `ReplaceRange`, any Graft +operation, or cross-head atomic filesystem-WAL persistence. Provider v1 remains +stable while consumers migrate; it is not renamed or silently reinterpreted as +the executable-operation corridor. The program digest supplies executable +meaning only: it cannot independently confer an operation coordinate, +invocability, or authority, and Echo cannot install or invoke it naked. The +admitted operation package binds the public contract and semantic closure to +the exact program, after which Echo independently admits each invocation. ## External Edict Provider Artifacts @@ -238,9 +238,10 @@ profiles and resolved effect write classes. Their canonical byte contract is Edict-owned and landed under Edict #157 in Edict PR #159. Generated resource declarations carry no output digests. Standard Edict resources and the self-contained provider CDDL are explicit trusted inputs from the Apache-2.0 -contract pack merged in Edict PR #162. Echo admits its exact CDDL, manifest, -contract/domain inventories, resource bytes, digests, and provenance before -generation without searching a filesystem, registry, or network. Schema +contract pack introduced in Edict PR #162 and extended with the +result-projection contract in Edict PR #174. Echo admits its exact CDDL, +manifest, contract/domain inventories, resource bytes, digests, and provenance +before generation without searching a filesystem, registry, or network. Schema instance validation is a separate output-admission step: exact `edict.canonical-cbor/v1` decoding is followed by validation against the named owning root in that authenticated CDDL. Passing both checks attests provider @@ -250,8 +251,9 @@ 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, -24 sorted schema bindings—nine invocation domains, the generated artifact -profile, and 14 generated-resource domains—and raw exact-byte hashes for all 24 +31 sorted schema bindings—nine compatibility invocation domains, the generated +artifact profile, 14 generated-resource domains, and seven generic +executable-operation closure 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 diff --git a/docs/spec/scheduler-warp-core.md b/docs/spec/scheduler-warp-core.md index b2471b03..e1d5b208 100644 --- a/docs/spec/scheduler-warp-core.md +++ b/docs/spec/scheduler-warp-core.md @@ -76,6 +76,16 @@ evaluation yields either a complete prepared candidate or a typed no-mutation obstruction. The scheduler reserves successful candidate footprints, constructs one composite consequence, and emits one Tick receipt entry per Action. +When the installed package carries a compiler-owned application-result +projection, the canonical invocation retains its exact application input and +private evaluation produces exact typed result bytes. The applied Action +outcome, Receipt, and WAL retain the projection identity, output type, canonical +bytes, and result identity. Recovery revalidates that evidence against the +installed projection. Obstructions carry no result, and neither evaluation nor +recovery invokes a native application callback. Admission rejects canonical +application input or a compiler-declared result ceiling above 65,536 bytes +before either value reaches private scheduler evaluation. + The successor state remains private until the complete Tick transaction is durable. Construction failure discards it. WAL failure restores the accepted-pending posture. The direct executable-operation prepare/commit methods diff --git a/docs/topics/GeneratedRules.md b/docs/topics/GeneratedRules.md index 81071440..5941e760 100644 --- a/docs/topics/GeneratedRules.md +++ b/docs/topics/GeneratedRules.md @@ -139,14 +139,16 @@ The currently implemented generic runtime slice is: exact canonical ExecutableOperationPackageV1 bytes -> Echo-owned package admission under a separate policy -> installed data-only EchoOperationProgramV1 --> exact basis-bearing canonical invocation +-> installed compiler-owned application-result projection +-> exact basis-bearing projected invocation with canonical application input -> canonical Action submission retained before acknowledgement -> Echo-owned invocation admission under authority and delegated budget -> ordinary head-inbox staging and scheduler selection at one exact basis -> bounded private evaluation with recorded actual footprint during Tick construction +-> exact typed application-result bytes and domain-separated identity -> deterministic composition of independent Actions into one Tick consequence -> typed committed, obstructed, or footprint-conflict outcome for every Action --> decided Tick WAL retention before publication and callback-free recovery +-> decided Tick WAL retention before publication and callback-free result recovery ``` The first two programs are an anchored typed-node alpha-attachment @@ -171,13 +173,15 @@ standalone application-owned Edict source -> exact Core, lawpack, exports, target adapter, target configuration, and Target IR -> compiler-produced ExecutableOperationPackageV1 -> structurally separate accepted verification report --> generic typed-input binding into one canonical Action +-> exact result-projection binding and generic typed-input binding +-> projected invocation retaining exact canonical application input -> accepted-submission WAL commit before acknowledgement -> fresh-host recovery of the exact installed package and pending Action -> scheduler-owned private evaluation of the recovered Action and one singleton Tick +-> exact compiler-declared result bytes in the committed outcome and Receipt -> decided-Tick WAL commit before publication --> second fresh-host package, Action, Tick, state, outcome, and Receipt recovery --> typed duplicate-create obstruction with no hidden mutation +-> second fresh-host package, Action, Tick, state, result, outcome, and Receipt recovery +-> typed duplicate-create obstruction with no hidden mutation or application result -> refusal to recover against a mutated initial state ``` @@ -189,16 +193,25 @@ configuration chain before Echo independently admits the package. Target configuration names the key and replacement input fields, node-id derivation, Action-lane WARP source, authority profile, type profiles, and budget. The accepted report's Target IR identity must equal the package semantic closure's -Target IR identity. Target configuration is selected from the adapter -implementation whose target intrinsic matches the package-supported program; -an unrelated effect cannot substitute a configuration with compatible profile -and budget values. State validation checks both the declared node type and the -attachment type. The retained report binds its reading to the input basis and -node key, derived worldline and node, accepted submission, committed Tick, and -typed Receipt identities. The runtime-owned basis selector, configured fields, -package meaning, and verification report all influence the canonical -invocation; no application matcher, executor, footprint callback, or -handwritten package participates. +Target IR identity, and its result-projection reference must equal the +compiler-owned projection bound into the package. Target configuration is +selected from the adapter implementation whose target intrinsic matches the +package-supported program; an unrelated effect cannot substitute a +configuration with compatible profile and budget values. State validation +checks both the declared node type and the attachment type. The retained report +binds its reading to the input basis and node key, derived worldline and node, +accepted submission, committed Tick, and typed Receipt identities. The +runtime-owned basis selector, configured fields, package meaning, and +verification report all influence the canonical invocation; no application +matcher, executor, footprint callback, or handwritten package participates. + +The generic report retains the projection identity, compiler-declared output +type coordinate, exact canonical result bytes, and domain-separated result +identity. The committed Receipt, recovered Action outcome, and recovered WAL +outcome must agree on all four propositions. Corrupting or coherently rebinding +the projection artifact fails independent Echo admission; substituting retained +result bytes fails recovery validation. The runner never decodes +application-specific fields in production. The duplicate witness reports the graph-only application-state root and typed target-value digest immediately before and after the obstructed Action. The diff --git a/docs/topics/WAL.md b/docs/topics/WAL.md index 655334fc..dbde296e 100644 --- a/docs/topics/WAL.md +++ b/docs/topics/WAL.md @@ -334,6 +334,16 @@ metadata are excluded from the application-state root because the obstruction legitimately extends causal history. It uses the strict filesystem adapter and no native application callback. +For a successful projected Action, the decided-Tick transaction also retains +the compiler-owned projection identity, output type coordinate, exact canonical +application-result bytes, and their domain-separated result identity. Recovery +deterministically re-evaluates the installed pure-data projection over the +exact application input retained by the original invocation and requires +byte-for-byte equality with that evidence before publishing the Action outcome +or Receipt. This verification performs no native callback and reads no current +application state. Rebound projection artifacts and substituted result bytes +therefore fail closed. An obstructed Action carries no application result. + The Action/Tick witnesses to read first are: - `accepted_executable_action_recovers_pending_before_scheduler_evaluation` diff --git a/schemas/edict-provider/README.md b/schemas/edict-provider/README.md index 39371ce2..3d8d4807 100644 --- a/schemas/edict-provider/README.md +++ b/schemas/edict-provider/README.md @@ -169,14 +169,16 @@ nor manifest. Independent fresh-store replay and separate host processes reproduce all three completed outcomes identically. Both checked components remain uninstalled package material; neither they nor the generated authority-facts documents are runtime Echo authority. The promoted lowerer is -230,285 bytes with SHA-256 -`9575ca8c843f3dfe4e5550ecdc40a8a8584c1aa7012b5b6f6a76e3f05f1b68f3`; the -promoted verifier is 247,754 bytes with SHA-256 -`d87f3df6cdeca0b14032a23b614e9b9ba1f53ea3955a5a0aebda6c61450c3e51`. +258,787 bytes with SHA-256 +`dfd14015705ff555a7efdb3787ddb0f8b4f304168a9a0ebf324fd25d430bf5cd`; the +promoted verifier is 277,836 bytes with SHA-256 +`279738ffeea40027eb493c15e873b87cf3aa0677a57f9f03fb824698e532322f`. External Edict contract inputs come from the checked -[`contracts/v1/`](contracts/v1/README.md) publication merged in -[Edict PR #162](https://github.com/flyingrobots/edict/pull/162). Echo passes the +[`contracts/v1/`](contracts/v1/README.md) publication introduced in +[Edict PR #162](https://github.com/flyingrobots/edict/pull/162) and extended +with the result-projection contract in +[Edict PR #174](https://github.com/flyingrobots/edict/pull/174). Echo passes the CDDL and manifest bytes explicitly to `provider_contract_pack::admit_provider_contract_pack_v1(...)`, which verifies the pinned publication identity, exact inventories, resource bytes, digests, @@ -285,8 +287,8 @@ independent host-side CDDL admission before that output is admitted. 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, 30 domain-to-root bindings (nine compatibility invocation domains, the -generated artifact profile, 14 generated-resource domains, and six generic +routes, 31 domain-to-root bindings (nine compatibility invocation domains, the +generated artifact profile, 14 generated-resource domains, and seven generic executable-operation closure 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 diff --git a/schemas/edict-provider/components/v1/README.md b/schemas/edict-provider/components/v1/README.md index fc9aaaee..53db5abd 100644 --- a/schemas/edict-provider/components/v1/README.md +++ b/schemas/edict-provider/components/v1/README.md @@ -23,8 +23,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 225,428 bytes with SHA-256 -`9575ca8c843f3dfe4e5550ecdc40a8a8584c1aa7012b5b6f6a76e3f05f1b68f3`. +The checked component is 258,787 bytes with SHA-256 +`dfd14015705ff555a7efdb3787ddb0f8b4f304168a9a0ebf324fd25d430bf5cd`. 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 @@ -35,9 +35,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 242,350 bytes +`wit-component` version recorded above. Its checked component is 277,836 bytes with SHA-256 -`d87f3df6cdeca0b14032a23b614e9b9ba1f53ea3955a5a0aebda6c61450c3e51`. +`279738ffeea40027eb493c15e873b87cf3aa0677a57f9f03fb824698e532322f`. 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 8ba4de4e..fc90817b 100644 Binary files a/schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm and b/schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm differ 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 284ccec0..b6c120b0 100644 Binary files a/schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm and b/schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm differ diff --git a/schemas/edict-provider/contracts/v1/README.md b/schemas/edict-provider/contracts/v1/README.md index 5dfc6f55..b03ebc57 100644 --- a/schemas/edict-provider/contracts/v1/README.md +++ b/schemas/edict-provider/contracts/v1/README.md @@ -3,9 +3,11 @@ # Edict Provider Contract Pack v1 -This directory vendors the exact Edict provider contract pack merged in -[Edict PR #162](https://github.com/flyingrobots/edict/pull/162) at commit -[`7cd8858c577fcfb6a05f0f617dfa821bb183c7df`](https://github.com/flyingrobots/edict/commit/7cd8858c577fcfb6a05f0f617dfa821bb183c7df): +This directory vendors the exact Edict provider contract pack introduced in +[Edict PR #162](https://github.com/flyingrobots/edict/pull/162) and extended +with `edict.result-projection.artifact/v1` in +[Edict PR #174](https://github.com/flyingrobots/edict/pull/174) at commit +[`21c4400faadf107e68906463d67c95532563c2ed`](https://github.com/flyingrobots/edict/commit/21c4400faadf107e68906463d67c95532563c2ed): - `edict-provider-contracts.cddl` is the assembled Edict-owned CDDL contract. - `manifest.json` binds that CDDL and its contract resources to their published diff --git a/schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl b/schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl index c3b2b5ad..5df2ec6a 100644 --- a/schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl +++ b/schemas/edict-provider/contracts/v1/edict-provider-contracts.cddl @@ -583,7 +583,7 @@ lawpack-adapter-budget = { } lawpack-adapter-write-class = "none" / "read" / "create" / "ensure" / - "append" / "modify" / "delete" + "append" / "replace" / "delete" / "custom" ; failure-ident is defined in edict-common.cddl. @@ -789,6 +789,45 @@ authority-budget-fact = { authority-write-class = "none" / "read" / "create" / "ensure" / "append" / "replace" / "delete" / "custom" +; --- edict-result-projection.cddl --- +; SPDX-License-Identifier: Apache-2.0 +; edict-result-projection.cddl +; Canonical schema for compiler-owned application-result projections. +; Authoritative byte encoding: edict.canonical-cbor/v1. + +result-projection = { + schema: "edict.result-projection/v1", + operationCoordinate: bounded-projection-text, + outputType: bounded-projection-text, + maxOutputBytes: uint .gt 0, + expression: result-projection-expr, +} + +result-projection-expr = result-projection-record / result-projection-source + +result-projection-record = { + kind: "record", + ; The root record counts as one of the Rust decoder's 256 expression nodes. + ; Nested aggregate node count remains an authoritative decoder check. + fields: { 0*255 bounded-projection-text => result-projection-expr }, +} + +result-projection-source = { + kind: "source", + source: result-projection-source-kind, + ; Matches MAX_RESULT_PROJECTION_PATH_SEGMENTS in edict-syntax. + path: [0*32 bounded-projection-text], +} + +result-projection-source-kind = + { kind: "applicationInput" } / + { + kind: "capabilityResult", + stepId: bounded-projection-text, + } + +bounded-projection-text = tstr .size (1..1024) + ; --- edict-target-ir.cddl --- ; SPDX-License-Identifier: Apache-2.0 ; edict-target-ir.cddl diff --git a/schemas/edict-provider/contracts/v1/manifest.json b/schemas/edict-provider/contracts/v1/manifest.json index f1cf149a..0106222a 100644 --- a/schemas/edict-provider/contracts/v1/manifest.json +++ b/schemas/edict-provider/contracts/v1/manifest.json @@ -3,8 +3,8 @@ "coordinate": "edict.provider-contract-pack.cddl@1", "license": "Apache-2.0", "schema": { - "bytesHex": "3b20535044582d4c6963656e73652d4964656e7469666965723a204170616368652d322e300a3b2065646963742d70726f76696465722d636f6e7472616374732e6364646c0a3b2047656e6572617465642066726f6d2045646963742d6f776e65642041424920667261676d656e74732e20444f204e4f5420454449542e0a0a3b202d2d2d2065646963742d636f6d6d6f6e2e6364646c202d2d2d0a3b2065646963742d636f6d6d6f6e2e6364646c0a3b20536861726564204344444c20747970657320666f722074686520456469637420414249732c20646566696e6564204f4e4345206865726520736f20746865792063616e6e6f742064726966740a3b202845444943542d4142492d4e4f4455502d303031292e2054776f2067726f7570733a0a3b2020202d207265736f757263652d7265662c207368613235362d6469676573742c206566666563742d6661696c7572652d626f64792c206566666563742d6b696e642c20617574686f726974792d636c6173732c0a3b2020202020636f72652d747970652d7265663a20617373656d626c656420776974682065646963742d7461726765742d70726f66696c652e6364646c20616e640a3b202020202065646963742d6c61777061636b2e6364646c20627920746865206275696c643b2074686f736520736368656d617320646f206e6f74207265646566696e65207468656d2e0a3b2020202d206f7065726174696f6e2d70726f66696c652c206f707469632d74656d706c6174652c2061706572747572652d726571756972656d656e7420616e6420746865697220726566733a0a3b2020202020636f6e73756d65642062792074686520436f72652f6f70746963206c61796572202865646963742d636f72652e6364646c2920616e64207265666572656e636564206279207468650a3b20202020206c616e67756167652f7461726765742d70726f66696c652073706563732e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a0a3b2041206e6f726d617469766520737562636f6d706f6e656e74207265666572656e636564206279206964656e7469747920706c7573206469676573742e204d616e696665737473206e657665720a3b20656d626564207468656972206f776e2073656c662d64696765737420696e20746865697220707265696d616765202845444943542d434f52452d53454c46484153482d303031292e0a7265736f757263652d726566203d207b2069643a20747374722c206469676573743a207368613235362d646967657374207d0a0a3b20446967657374732061726520617574686f726974617469766520617320747970656420627974652076616c7565732c206e657665722068657820737472696e67732e20526576696577204a534f4e0a3b2072656e64657273207468697320617320227368613235363a3c3634206c6f77657263617365206865783e22202845444943542d4449474553542d574952452d303031292e0a7368613235362d646967657374203d205b20616c676f726974686d3a2022736861323536222c2062797465733a2062737472202e73697a65203332205d0a0a3b2041206e616d6564206c6f772d6c6576656c206661696c75726520616e206566666563742063616e2072616973652e2054686520736f75726365206f62737472756374696f6e206d61700a3b2062696e64732069742028627920636f6f7264696e6174652920616e6420636f6e73747275637473206120747970656420646f6d61696e206f62737472756374696f6e2066726f6d206974730a3b207061796c6f6164202845444943542d4142492d4641494c5552452d4e414d45442d303031292e0a3b20416e20656666656374277320606566666563744661696c7572657360206c697374204d555354206861766520756e697175652060636f6f7264696e61746560733a2073696e6365207468650a3b206f62737472756374696f6e206d6170206973206b6579656420627920636f6f7264696e6174652c2074776f206661696c757265732073686172696e67206120636f6f7264696e61746520286576656e0a3b207769746820646966666572656e7420617574686f72697479436c6173732f7061796c6f61645479706529206d616b652065786861757374697665206d617070696e6720616e642062696e6465720a3b20747970696e6720616d626967756f757320616e64206172652072656a6563746564202845444943542d4142492d4641494c5552452d554e495155452d303031292e0a3b0a3b2045666665637473206361727279207468656972206661696c757265732061732061206d617020607b206661696c7572652d6964656e74203d3e206566666563742d6661696c7572652d626f6479207d600a3b202873656520746865207461726765742f6c61777061636b2065666665637420736368656d6173292e20546865206661696c75726520636f6f7264696e61746520697320746865206d61700a3b204b45592c20736f206974206973206e6f7420726570656174656420696e2074686520626f647920616e642063616e6e6f74206469736167726565207769746820746865206b65792e0a6566666563742d6661696c7572652d626f6479203d207b0a2020617574686f72697479436c6173733a20617574686f726974792d636c6173732c0a20207061796c6f6164547970653a20636f72652d747970652d7265662c202020202020202020202020203b2074797065642c20626f756e64656420286d617920626520656d707479207265636f7264290a7d0a0a3b2041206661696c75726520636f6f7264696e617465206d7573742062652061206261726520456469637420606964656e746020286c65747465722f756e64657273636f7265207468656e0a3b206c6574746572732f6469676974732f756e64657273636f7265732920414e44206d757374206e6f742062652061207265736572766564206b6579776f72642028652e672e2060656c7365602c0a3b20606261736973602c20607768657265602c206072657175697265602c2060666f72602c2060696660292e2054686520736f75726365206f62737472756374696f6e2d6d6170204c4853206f6e6c790a3b20616363657074732061206e6f6e2d6b6579776f726420606964656e74602c20736f20612068797068656e2f646f742f6b6579776f726420636f6f7264696e61746520776f756c642062650a3b204142492d76616c69642079657420696d706f737369626c6520746f206d617020657868617573746976656c7920696e20736f757263652e20546865207265676578206361707475726573207468650a3b206c65786963616c2073686170653b206b6579776f7264206578636c7573696f6e20697320616e206164646974696f6e616c2076616c69646174696f6e2072756c650a3b202845444943542d4142492d4641494c5552452d4944454e542d303031292e0a6661696c7572652d6964656e74203d2074737472202e72656765787020225b412d5a612d7a5f5d5b412d5a612d7a302d395f5d2a220a0a6566666563742d6b696e64203d20227265616422202f202263726561746522202f2022656e7375726522202f20227265706c61636522202f202264656c65746522202f0a202020202020202020202020202022617070656e6422202f202272656475636522202f202273656d616e7469632e656d697422202f2022637573746f6d220a0a617574686f726974792d636c617373203d2022646f6d61696e4d61707061626c6522202f20227061727469636970616e744f776e656422202f2022696e746567726974794661756c7422202f0a202020202020202020202020202020202020227265736f757263654661756c7422202f2022696e7465726e616c4661756c74220a0a636f72652d747970652d726566203d20747374722020203b2063616e6f6e6963616c20436f7265207479706520636f6f7264696e6174650a0a3b20416e206f7065726174696f6e2070726f66696c6520737570706c69657320746865206f707469632074656d706c617465206120436f726520696e74656e74207265736f6c766573206974730a3b206f707469634b696e642f626f756e646172794b696e642f737570706f7274506f6c6963792f6c6f7373446973706f736974696f6e2066726f6d2e205461726765742070726f66696c657320616e640a3b206c61777061636b73207075626c6973682074686573652061732061206d617020607b20636f6f7264696e617465203d3e206f7065726174696f6e2d70726f66696c65207d602c20736f207468650a3b20636f6f7264696e61746520697320746865204b45592c206e6f7420612076616c7565206669656c64202845444943542d4f505449432d54454d504c4154452d4f574e45522d3030312c0a3b2045444943542d4142492d4f5050524f46494c452d554e495155452d303031292e0a6f7065726174696f6e2d70726f66696c65203d207b0a20206f7074696354656d706c6174653a206f707469632d74656d706c6174652c0a20206566666563745072656469636174653a20747374722c20202020202020202020203b20636f6f7264696e617465206f6620746865206f7065726174696f6e2d6d6f6465207072656469636174650a7d0a0a6f707469632d74656d706c617465203d207b0a20206f707469634b696e643a2022726576656c6174696f6e22202f20226166666563745265696e746567726174696f6e222c0a2020626f756e646172794b696e643a202270726f6a656374696f6e22202f2022616666656374222c0a2020737570706f7274506f6c6963793a20747374722c202020202020202020202020203b2063616e6f6e6963616c20737570706f72742d706f6c69637920636f6f7264696e6174650a20206c6f7373446973706f736974696f6e3a20747374722c20202020202020202020203b2063616e6f6e6963616c206c6f73732d646973706f736974696f6e20636f6f7264696e6174650a20203f20626173697354656d706c6174653a20747374722c20202020202020202020203b206f7074696f6e616c206469676573742d6c6f636b65642062617369732074656d706c61746520636f6f72640a20203b2074686520617065727475726520726571756972656d656e7420746869732074656d706c61746520737570706c6965732e205265717569726564207768656e207468652074656d706c6174650a20203b2069732074686520736f75726365206f66206120436f7265206f707469632773206170657274757265526571756972656d656e742028692e652e2074686520696e74656e7420686173206e6f0a20203b20736f757263652060666f6f747072696e74203c3d202e2e2e60292c2073696e6365206170657274757265526571756972656d656e74206973206d616e6461746f727920696e20436f72650a20203b202845444943542d4f505449432d41504552545552452d5245462d303031292e0a20203f206170657274757265526571756972656d656e743a2061706572747572652d726571756972656d656e742c0a7d0a0a3b206170657274757265526571756972656d656e742069732061207479706564207265666572656e63652c206e65766572206120667265652d666f726d20737472696e672e2041207265766965770a3b2072656e646572696e67206d61792073686f772069747320636f6f7264696e617465202845444943542d4f505449432d41504552545552452d5245462d303031292e0a61706572747572652d726571756972656d656e74203d20666f6f747072696e742d6365696c696e672d726566202f2061627374726163742d666f6f747072696e742d6f626c69676174696f6e2d7265660a666f6f747072696e742d6365696c696e672d726566203d207b206b696e643a2022666f6f747072696e744365696c696e67222c207265663a2074737472207d0a61627374726163742d666f6f747072696e742d6f626c69676174696f6e2d726566203d207b206b696e643a20226162737472616374466f6f747072696e744f626c69676174696f6e222c207265663a2074737472207d0a0a3b202d2d2d2065646963742d636f72652e6364646c202d2d2d0a3b2065646963742d636f72652e6364646c0a3b204e6f726d617469766520736368656d6120666f722074686520456469637420436f72652076312073656d616e746963206d6f64656c2e0a3b0a3b2053636f706520626f756e646172793a20746869732066696c6520646566696e657320436f7265206d65616e696e6720616e6420736368656d61207368617065206f6e6c792e20497420646f65730a3b206e6f7420646566696e6520612063616e6f6e6963616c20656e636f6465722c20436f7265206d6f64756c652068617368206669656c64732c20686173682066697874757265732c207461726765740a3b206c6f776572696e672c2061646d697373696f6e2062756e646c65732c206f72207461726765742d6f776e65642049522e0a0a636f72652d6d6f64756c65203d207b0a202061706956657273696f6e3a202265646963742e636f72652f7631222c0a2020636f6f7264696e6174653a20747374722c0a2020696d706f7274733a205b2a20636f72652d696d706f72745d2c0a202074797065733a207b202a2074737472203d3e20636f72652d74797065207d2c0a2020696e74656e74733a207b202b2074737472203d3e20636f72652d696e74656e74207d2c0a20207265717569726564436f72654361706162696c69746965733a205b2a20747374725d2c0a7d0a0a636f72652d696d706f7274203d207b0a20206b696e643a20226c61777061636b22202f202274617267657422202f2022636f7265222c0a20207265663a207265736f757263652d7265662c0a20203f20616c6961733a20747374722c0a7d0a0a3b202d2d2d207479706573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a636f72652d74797065203d20636f72652d7363616c61722d74797065202f20636f72652d7265636f72642d74797065202f20636f72652d76617269616e742d74797065202f0a202020202020202020202020636f72652d6f7074696f6e2d74797065202f20636f72652d6c6973742d74797065202f20636f72652d6d61702d74797065202f0a202020202020202020202020636f72652d6361706162696c6974792d7265662d747970650a0a636f72652d7363616c61722d74797065203d20636f72652d626f6f6c2d74797065202f20636f72652d696e742d74797065202f20636f72652d737472696e672d74797065202f0a20202020202020202020202020202020202020636f72652d62797465732d74797065202f20636f72652d756e69742d747970650a0a636f72652d626f6f6c2d74797065203d207b206b696e643a2022426f6f6c22207d0a636f72652d756e69742d74797065203d207b206b696e643a2022556e697422207d0a636f72652d696e742d74797065203d207b0a20206b696e643a202249363422202f202255363422202f202249333222202f202255333222202f202249313622202f202255313622202f2022493822202f20225538222c0a7d0a636f72652d737472696e672d74797065203d207b0a20206b696e643a2022537472696e67222c0a20206d61783a2075696e742c0a202063616e6f6e6963616c3a2022756e69636f64652d7363616c61722d6e666322202f20227261772d75746638222c0a7d0a636f72652d62797465732d74797065203d207b0a20206b696e643a20224279746573222c0a20206d61783a2075696e742c0a7d0a636f72652d7265636f72642d74797065203d207b0a20206b696e643a20225265636f7264222c0a20206669656c64733a207b202a2074737472203d3e20636f72652d747970652d726566207d2c0a7d0a636f72652d76617269616e742d74797065203d207b0a20206b696e643a202256617269616e74222c0a202063617365733a207b202b2074737472203d3e2076617269616e742d636173652d626f6479207d2c0a7d0a76617269616e742d636173652d626f6479203d207b0a20203f207061796c6f61643a20636f72652d747970652d7265662c0a7d0a636f72652d6f7074696f6e2d74797065203d207b0a20206b696e643a20224f7074696f6e222c0a20206974656d3a20636f72652d747970652d7265662c0a7d0a636f72652d6c6973742d74797065203d207b0a20206b696e643a20224c697374222c0a20206974656d3a20636f72652d747970652d7265662c0a20206d61783a2075696e742c0a7d0a636f72652d6d61702d74797065203d207b0a20206b696e643a20224d6170222c0a20206b65793a20636f72652d747970652d7265662c0a202076616c75653a20636f72652d747970652d7265662c0a20206d61783a2075696e742c0a7d0a636f72652d6361706162696c6974792d7265662d74797065203d207b0a20206b696e643a20224361706162696c697479526566222c0a20206974656d3a20636f72652d747970652d7265662c0a7d0a0a3b20636f72652d747970652d72656620697320646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d612e0a0a3b202d2d2d207265666572656e63657320616e642076616c756573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a3b204c6f63616c206964656e7469747920697320616c7068612d737461626c652e20606964602069732074686520636f6d70696c65722d6f776e6564206c6f63616c20636f6f7264696e6174653b0a3b2060616c7068614e616d656020697320746865206e6f726d616c697a65642068756d616e2f6465627567206e616d652e20536f757263652062696e646572207370656c6c696e67206973206e6f740a3b206964656e746974792e0a6c6f63616c2d726566203d207b0a202069643a20747374722c0a2020616c7068614e616d653a20747374722c0a2020747970653a20636f72652d747970652d7265662c0a7d0a0a636f72652d76616c7565203d20636f72652d6e756c6c2d76616c7565202f20636f72652d626f6f6c2d76616c7565202f20636f72652d696e742d76616c7565202f0a20202020202020202020202020636f72652d737472696e672d76616c7565202f20636f72652d62797465732d76616c7565202f20636f72652d7265636f72642d76616c7565202f0a20202020202020202020202020636f72652d76617269616e742d76616c7565202f20636f72652d6c6973742d76616c7565202f20636f72652d6d61702d76616c7565202f0a20202020202020202020202020636f72652d6361706162696c6974792d76616c75650a0a636f72652d6e756c6c2d76616c7565203d207b206b696e643a20226e756c6c22207d0a636f72652d626f6f6c2d76616c7565203d207b206b696e643a2022626f6f6c222c2076616c75653a20626f6f6c207d0a636f72652d696e742d76616c7565203d207b206b696e643a2022696e74222c2077696474683a20747374722c2076616c75653a20696e74207d0a636f72652d737472696e672d76616c7565203d207b206b696e643a2022737472696e67222c2076616c75653a2074737472207d0a636f72652d62797465732d76616c7565203d207b206b696e643a20226279746573222c2076616c75653a2062737472207d0a636f72652d7265636f72642d76616c7565203d207b206b696e643a20227265636f7264222c206669656c64733a207b202a2074737472203d3e20636f72652d76616c7565207d207d0a636f72652d76617269616e742d76616c7565203d207b0a20206b696e643a202276617269616e74222c0a2020747970653a20636f72652d747970652d7265662c0a2020636173653a20747374722c0a20203f207061796c6f61643a20636f72652d76616c75652c0a7d0a636f72652d6c6973742d76616c7565203d207b206b696e643a20226c697374222c2076616c7565733a205b2a20636f72652d76616c75655d207d0a636f72652d6d61702d76616c7565203d207b206b696e643a20226d6170222c20656e74726965733a205b2a205b6b65793a20636f72652d76616c75652c2076616c75653a20636f72652d76616c75655d5d207d0a636f72652d6361706162696c6974792d76616c7565203d207b0a20206b696e643a20226361706162696c697479222c0a2020726563656970743a207368613235362d6469676573742c0a7d0a0a3b2045646963742d617574686f72656420707572652068656c70657273207573652061207075726520436f72652066756e6374696f6e20626f64792e2054686520626f64792063616e2062696e640a3b20707572652065787072657373696f6e7320616e642072657475726e20616e2065787072657373696f6e2c206275742069742063616e6e6f7420636f6e7461696e20436f7265206566666563742c0a3b2067756172642c206272616e63682c206c6f6f702c206d617463682d6e6f64652c206f722070726f6f662d6f626c69676174696f6e206e6f6465732e0a636f72652d666e2d626f6479203d207b0a2020706172616d733a205b2a206c6f63616c2d7265665d2c0a2020626f64793a20636f72652d707572652d626c6f636b2c0a7d0a0a636f72652d707572652d626c6f636b203d207b0a20206c6f63616c733a205b2a206c6f63616c2d7265665d2c0a202062696e64696e67733a205b2a20707572652d6c65742d6e6f64655d2c0a2020726573756c743a20636f72652d657870722c0a7d0a0a707572652d6c65742d6e6f6465203d207b0a20206b696e643a20226c6574222c0a202062696e64696e673a206c6f63616c2d7265662c0a202076616c75653a20636f72652d657870722c0a7d0a0a3b202d2d2d2065787072657373696f6e7320616e642070726564696361746573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a636f72652d65787072203d206c6f63616c2d65787072202f20636f6e73742d65787072202f207265636f72642d65787072202f206669656c642d65787072202f0a20202020202020202020202076617269616e742d65787072202f206d617463682d65787072202f2063616c6c2d65787072202f206c6973742d65787072202f206d61702d65787072202f0a20202020202020202020202069662d657870720a0a6c6f63616c2d65787072203d207b206b696e643a20226c6f63616c222c207265663a206c6f63616c2d726566207d0a636f6e73742d65787072203d207b206b696e643a2022636f6e7374222c2076616c75653a20636f72652d76616c7565207d0a7265636f72642d65787072203d207b206b696e643a20227265636f7264222c206669656c64733a207b202a2074737472203d3e20636f72652d65787072207d207d0a6669656c642d65787072203d207b206b696e643a20226669656c64222c20626173653a20636f72652d657870722c206669656c643a2074737472207d0a76617269616e742d65787072203d207b0a20206b696e643a202276617269616e74222c0a2020747970653a20636f72652d747970652d7265662c0a2020636173653a20747374722c0a20203f207061796c6f61643a20636f72652d657870722c0a7d0a6d617463682d65787072203d207b0a20206b696e643a20226d61746368222c0a20207363727574696e65653a20636f72652d657870722c0a202061726d733a205b2b206d617463682d61726d5d2c0a7d0a6d617463682d61726d203d207b0a2020636173653a20747374722c0a20203f2062696e6465723a206c6f63616c2d7265662c0a2020626f64793a20636f72652d657870722c0a7d0a63616c6c2d65787072203d207b0a20206b696e643a202263616c6c222c0a202063616c6c65653a20747374722c0a202074797065417267733a205b2a20636f72652d747970652d7265665d2c0a2020617267733a205b2a20636f72652d657870725d2c0a7d0a6c6973742d65787072203d207b206b696e643a20226c697374222c2076616c7565733a205b2a20636f72652d657870725d207d0a6d61702d65787072203d207b206b696e643a20226d6170222c20656e74726965733a205b2a205b6b65793a20636f72652d657870722c2076616c75653a20636f72652d657870725d5d207d0a69662d65787072203d207b0a20206b696e643a20226966222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20207468656e3a20636f72652d657870722c0a2020656c73653a20636f72652d657870722c0a7d0a0a636f72652d707265646963617465203d20747275652d707265646963617465202f2066616c73652d707265646963617465202f206e6f742d707265646963617465202f0a2020202020202020202020202020202020616c6c2d707265646963617465202f20616e792d707265646963617465202f20636f6d706172652d707265646963617465202f0a202020202020202020202020202020202063616c6c2d707265646963617465202f206f62737472756374696f6e2d7072656469636174650a0a747275652d707265646963617465203d207b206b696e643a20227472756522207d0a66616c73652d707265646963617465203d207b206b696e643a202266616c736522207d0a6e6f742d707265646963617465203d207b206b696e643a20226e6f74222c2076616c75653a20636f72652d707265646963617465207d0a616c6c2d707265646963617465203d207b206b696e643a2022616c6c222c2076616c7565733a205b2b20636f72652d7072656469636174655d207d0a616e792d707265646963617465203d207b206b696e643a2022616e79222c2076616c7565733a205b2b20636f72652d7072656469636174655d207d0a636f6d706172652d707265646963617465203d207b0a20206b696e643a2022636f6d70617265222c0a20206f703a20223d3d22202f2022213d22202f20223c22202f20223c3d22202f20223e22202f20223e3d222c0a20206c6566743a20636f72652d657870722c0a202072696768743a20636f72652d657870722c0a7d0a63616c6c2d707265646963617465203d207b0a20206b696e643a202263616c6c222c0a20207072656469636174653a20747374722c0a2020617267733a205b2a20636f72652d657870725d2c0a7d0a6f62737472756374696f6e2d707265646963617465203d207b0a20206b696e643a20226f62737472756374696f6e222c0a2020636f6f7264696e6174653a206661696c7572652d6964656e742c0a20207061796c6f61643a20636f72652d657870722c0a7d0a0a696e7075742d636f6e73747261696e74203d207b0a2020636f6f7264696e6174653a20747374722c0a2020736f757263653a2022776865726522202f2022636f6d70696c6572222c0a20207072656469636174653a20636f72652d7072656469636174652c0a7d0a0a3b202d2d2d20696e74656e74732c20626c6f636b732c20616e64206e6f646573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a636f72652d696e74656e74203d207b0a2020696e7075743a20636f72652d747970652d7265662c0a20206f75747075743a20636f72652d747970652d7265662c0a202072657175697265644f7065726174696f6e50726f66696c653a20747374722c0a20203f2062617369733a20636f72652d657870722c0a2020696e707574436f6e73747261696e74733a205b2a20696e7075742d636f6e73747261696e745d2c0a2020636f72654576616c756174696f6e4275646765743a20636f72652d6275646765742c0a2020626f64793a20636f72652d626c6f636b2c0a20203f206f707469633a20636f72652d6f707469632c0a7d0a0a636f72652d627564676574203d207b0a20206d617853746570733a2075696e742c0a20206d6178416c6c6f636174656442797465733a2075696e742c0a20206d61784f757470757442797465733a2075696e742c0a7d0a0a636f72652d6f70746963203d207b0a20206f707469634b696e643a2022726576656c6174696f6e22202f20226166666563745265696e746567726174696f6e222c0a2020626f756e646172794b696e643a202270726f6a656374696f6e22202f2022616666656374222c0a20206170657274757265526571756972656d656e743a2061706572747572652d726571756972656d656e742c0a2020737570706f7274506f6c6963793a20747374722c0a20206c6f7373446973706f736974696f6e3a20747374722c0a7d0a0a636f72652d626c6f636b203d207b0a20206c6f63616c733a205b2a206c6f63616c2d7265665d2c0a20206e6f6465733a205b2a20636f72652d6e6f64655d2c0a2020726573756c743a20636f72652d657870722c0a7d0a0a636f72652d6e6f6465203d206c65742d6e6f6465202f20726571756972652d6e6f6465202f206566666563742d6e6f6465202f2067756172642d6e6f6465202f206272616e63682d6e6f6465202f0a202020202020202020202020666f722d6e6f6465202f206d617463682d6e6f6465202f2070726f6f662d6f626c69676174696f6e2d6e6f64650a0a6c65742d6e6f6465203d207b0a20206b696e643a20226c6574222c0a202062696e64696e673a206c6f63616c2d7265662c0a202076616c75653a20636f72652d657870722c0a7d0a726571756972652d6e6f6465203d207b0a20206b696e643a202272657175697265222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20206f6e4661696c7572653a20726571756972652d6661696c7572652d61726d2c0a7d0a726571756972652d6661696c7572652d61726d203d207465726d696e616c2d726571756972652d6661696c757265202f0a20202020202020202020202020202020202020202020636f6e74696e75652d6f6273747275637465642d726571756972652d6661696c7572650a7465726d696e616c2d726571756972652d6661696c757265203d207b0a20206b696e643a20227465726d696e616c222c0a2020726561736f6e3a206f62737472756374696f6e2d726561736f6e2c0a7d0a636f6e74696e75652d6f6273747275637465642d726571756972652d6661696c757265203d207b0a20206b696e643a2022636f6e74696e75654f627374727563746564222c0a2020726561736f6e3a206f62737472756374696f6e2d726561736f6e2c0a7d0a6f62737472756374696f6e2d726561736f6e203d207b0a2020726561736f6e4b696e643a20747374722c0a20207061796c6f61643a207b202a2074737472203d3e20636f72652d65787072207d2c0a7d0a6566666563742d6e6f6465203d207b0a20206b696e643a2022656666656374222c0a202062696e64696e673a206c6f63616c2d7265662c0a20206566666563743a20747374722c0a2020696e7075743a20636f72652d657870722c0a20206f62737472756374696f6e4d61703a207b202a206661696c7572652d6964656e74203d3e206f62737472756374696f6e2d61726d207d2c0a7d0a6f62737472756374696f6e2d61726d203d207b0a202062696e6465723a206c6f63616c2d7265662c0a202076616c75653a20636f72652d657870722c0a7d0a67756172642d6e6f6465203d207b0a20206b696e643a20226775617264222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20206f62737472756374696f6e3a20636f72652d657870722c0a7d0a6272616e63682d6e6f6465203d207b0a20206b696e643a20226272616e6368222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20207468656e3a20636f72652d626c6f636b2c0a2020656c73653a20636f72652d626c6f636b2c0a7d0a666f722d6e6f6465203d207b0a20206b696e643a2022666f72222c0a202062696e6465723a206c6f63616c2d7265662c0a2020697465723a20636f72652d657870722c0a2020626f756e643a20636f72652d626f756e642c0a2020626f64793a20636f72652d626c6f636b2c0a7d0a6d617463682d6e6f6465203d207b0a20206b696e643a20226d61746368222c0a20207363727574696e65653a20636f72652d657870722c0a202061726d733a205b2b206d617463682d626c6f636b2d61726d5d2c0a7d0a6d617463682d626c6f636b2d61726d203d207b0a2020636173653a20747374722c0a20203f2062696e6465723a206c6f63616c2d7265662c0a2020626f64793a20636f72652d626c6f636b2c0a7d0a70726f6f662d6f626c69676174696f6e2d6e6f6465203d207b0a20206b696e643a202270726f6f66222c0a2020636f6f7264696e6174653a20747374722c0a20207072656469636174653a20636f72652d7072656469636174652c0a7d0a0a636f72652d626f756e64203d206c69746572616c2d626f756e64202f20636f6f7264696e6174652d626f756e640a6c69746572616c2d626f756e64203d207b206b696e643a20226c69746572616c222c2076616c75653a2075696e74207d0a636f6f7264696e6174652d626f756e64203d207b206b696e643a2022636f6f7264696e617465222c207265663a2074737472207d0a0a3b20536861726564207265736f757263652d7265662c207368613235362d6469676573742c206661696c7572652d6964656e742c2061706572747572652d726571756972656d656e742c20616e640a3b20636f72652d747970652d7265662061726520646566696e6564206f6e636520696e2065646963742d636f6d6d6f6e2e6364646c2e0a0a3b202d2d2d2065646963742d6c61777061636b2e6364646c202d2d2d0a3b2065646963742d6c61777061636b2e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f7220746865204564696374206c61777061636b206d616e696665737420616e64206578706f727420737572666163652e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e204a534f4e20696e207468652070726f73652073706563730a3b2069732061207265766965772072656e646572696e672067656e6572617465642066726f6d207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a6c61777061636b2d6d616e6966657374203d207b0a202061706956657273696f6e3a202265646963742e6c61777061636b2f7631222c0a202069643a20747374722c0a202076657273696f6e3a20747374722c0a20206163636570746564436f72654162693a205b2b20747374725d2c0a2020646570656e64656e636965733a205b2a206c61777061636b2d6465705d2c202020202020202020203b20616379636c69632c206469676573742d6c6f636b6564202845444943542d4c41575041434b2d4441472d303031290a20206578706f7274733a207265736f757263652d7265662c0a20203f2074617267657441646170746572733a205b2b207461726765742d616461707465725d2c2020203b207265717569726564206f6e6c7920696620616e792072756e74696d6520656666656374206578697374730a20203f2068656c706572436f6d706f6e656e743a2065786563757461626c652d636f6d706f6e656e742c203b2065786563757461626c652068656c70657273206361727279207468656972206f776e2073616e64626f782b6675656c0a202076657269666965723a2076657269666965722c202020202020202020202020202020202020202020203b20636c61737369666965643a206465636c61726174697665206f722065786563757461626c650a2020636f6d7061746962696c6974793a207265736f757263652d7265662c0a2020636f6e666f726d616e636546697874757265436f727075733a207265736f757263652d7265662c0a7d0a0a3b2041207665726966696572206973206569746865722061206465636c617261746976652072756c6573657420286e6f2072756e74696d6529206f7220616e2065786563757461626c650a3b20636f6d706f6e656e742e20416e2065786563757461626c65207665726966696572204d55535420636172727920697473206f776e2073616e64626f7820616e64206675656c206d6f64656c2c0a3b20736f2074686520736368656d6120656e666f726365732074686174206e6f2065786563757461626c6520636f6d706f6e656e74206973206c65667420756e626f756e6465640a3b202845444943542d4142492d56455249464945522d424f554e442d303031292e0a7665726966696572203d206465636c617261746976652d7665726966696572202f2065786563757461626c652d76657269666965720a6465636c617261746976652d7665726966696572203d207b20636c6173733a20226465636c61726174697665222c2072756c657365743a207265736f757263652d726566207d0a65786563757461626c652d7665726966696572203d207b0a2020636c6173733a202265786563757461626c65222c0a2020636f6d706f6e656e743a207265736f757263652d7265662c0a202073616e64626f783a207265736f757263652d7265662c0a20206675656c4d6f64656c3a207265736f757263652d7265662c0a7d0a0a3b20416e792065786563757461626c6520636f6d706f6e656e7420697320626f756e64656420627920697473206f776e2073616e64626f78202b206675656c206d6f64656c2e0a65786563757461626c652d636f6d706f6e656e74203d207b0a2020636f6d706f6e656e743a207265736f757263652d7265662c0a202073616e64626f783a207265736f757263652d7265662c0a20206675656c4d6f64656c3a207265736f757263652d7265662c0a7d0a0a6c61777061636b2d646570203d207b2069643a20747374722c2076657273696f6e3a20747374722c206469676573743a207368613235362d646967657374207d0a0a3b20416461707465722073656c656374696f6e206b65797320534f4c454c59206f666620746865206469676573742d6c6f636b65642060616363657074656454617267657450726f66696c65600a3b20286974732060696460206973207468652070726f66696c652069643b206974732060646967657374602070696e73207468652065786163742070726f66696c652f76657273696f6e292e2054686572650a3b20617265206e6f20696e646570656e64656e7420646973706c617920737472696e6773207468617420636f756c64206469736167726565207769746820746865206c6f636b2c20736f20610a3b207265736f6c7665722063616e6e6f742062696e6420616e206164617074657220746f206f6e6520746172676574207768696c6520746865206c6f636b2070726f76657320616e6f746865720a3b202845444943542d4c41575041434b2d414441505445522d54415247455449522d303031292e0a7461726765742d61646170746572203d207b0a2020616363657074656454617267657450726f66696c653a207265736f757263652d7265662c202020203b206469676573742d6c6f636b65642c20617574686f72697461746976652073656c6563746f720a2020616363657074656454617267657449723a207265736f757263652d7265662c2020202020202020203b206469676573742d6c6f636b65640a2020616461707465723a207265736f757263652d7265662c0a7d0a0a3b20536861726564207479706573207265736f757263652d72656620616e64207368613235362d6469676573742061726520646566696e6564206f6e636520696e0a3b2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a3b202d2d2d206578706f72742073757266616365202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a6c61777061636b2d6578706f727473203d207b0a202074797065733a205b2a206578706f727465642d747970655d2c0a2020636f6e7374616e74733a205b2a206578706f727465642d636f6e7374616e745d2c0a20207075726546756e6374696f6e733a205b2a20707572652d66756e6374696f6e5d2c0a2020656666656374733a205b2a2073656d616e7469632d6566666563745d2c0a20206f62737472756374696f6e733a205b2a206f62737472756374696f6e2d6465665d2c0a20203b206b65796564206279206f7065726174696f6e2d70726f66696c6520636f6f7264696e61746520e2869220756e697175656e65737320656e666f726365640a20203b202845444943542d4142492d4f5050524f46494c452d554e495155452d303031290a20203b206f7065726174696f6e2d70726f66696c65207265636f7264732074686973206c61777061636b206578706f72747320286f707469632074656d706c6174657320746861740a20203b2060696d706c656d656e7473602f6070726f66696c656020636c6175736573207265736f6c766520616761696e7374292e206f7065726174696f6e2d70726f66696c652069730a20203b20646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c202845444943542d4142492d4f5050524f46494c452d534c4f542d303031292e0a20206f7065726174696f6e50726f66696c65733a207b202a2074737472203d3e206f7065726174696f6e2d70726f66696c65207d2c20203b206b6579656420627920636f6f7264696e6174650a7d0a0a6578706f727465642d7479706520202020203d207b20636f6f7264696e6174653a20747374722c20646566696e6974696f6e3a20636f72652d747970652d726566207d0a6578706f727465642d636f6e7374616e74203d207b20636f6f7264696e6174653a20747374722c20747970653a20636f72652d747970652d7265662c2076616c75653a20616e79207d0a0a3b204120707572652068656c7065722069732061206469736372696d696e6174656420756e696f6e2062792060736f75726365602c20736f2074686520736368656d6120697473656c660a3b2067756172616e7465657320616e20696d706c656d656e746174696f6e20657869737473202845444943542d4c41575041434b2d505552452d494d504c2d303031293a0a3b2020202d20226564696374223a20617574686f72656420696e2045646963742f436f72653b2074686520436f726520626f6479206973206361727269656420696e6c696e6520286861736865640a3b20202020207769746820746865206578706f72742073757266616365292e2054686520736368656d61207265717569726573207468652060626f647960206669656c642e0a3b2020202d2022636f6d706f6e656e74223a20696d706c656d656e746564206f7574736964652045646963743b2063617272696573206e6f20696e6c696e6520626f647920616e6420696e73746561640a3b20202020206361727269657320697473206f776e206469676573742d6c6f636b65642060696d706c656d656e746174696f6e60202873616e64626f78202b206675656c292e20497420646f65730a3b20202020206e6f7420646570656e64206f6e20746865206f7074696f6e616c206d616e69666573742d6c6576656c2068656c706572436f6d706f6e656e742e0a707572652d66756e6374696f6e203d2065646963742d707572652d66756e6374696f6e202f20636f6d706f6e656e742d707572652d66756e6374696f6e0a0a707572652d66756e6374696f6e2d636f6d6d6f6e203d20280a2020636f6f7264696e6174653a20747374722c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020706172616d6574657254797065733a205b2a20636f72652d747970652d7265665d2c2020202020203b20616c6c20626f756e6465640a202072657475726e547970653a20636f72652d747970652d7265662c20202020202020202020202020203b20626f756e6465640a2020636f737454656d706c6174653a20747374722c0a202064657465726d696e69736d436c6173733a2022746f74616c22202f2022746f74616c2d776974682d74797065642d646961676e6f73746963222c0a290a0a65646963742d707572652d66756e6374696f6e203d207b0a2020707572652d66756e6374696f6e2d636f6d6d6f6e2c0a2020736f757263653a20226564696374222c0a2020626f64793a20636f72652d666e2d626f64792c2020202020202020202020202020202020202020203b20696e6c696e652c20686173682d7369676e69666963616e740a7d0a0a636f6d706f6e656e742d707572652d66756e6374696f6e203d207b0a2020707572652d66756e6374696f6e2d636f6d6d6f6e2c0a2020736f757263653a2022636f6d706f6e656e74222c0a20203b20746865206469676573742d6c6f636b656420636f6d706f6e656e7420696d706c656d656e74696e6720746869732068656c7065722e2052657175697265642061742074686520736368656d610a20203b206c6576656c20736f206120636f6d706f6e656e742068656c7065722063616e206e657665722076616c696461746520776974686f7574206120686173682d626f756e642c0a20203b2073616e64626f782b6675656c2d64657363726962656420696d706c656d656e746174696f6e202845444943542d4c41575041434b2d505552452d494d504c2d303031292e0a2020696d706c656d656e746174696f6e3a2065786563757461626c652d636f6d706f6e656e742c0a7d0a0a3b20636f72652d666e2d626f647920697320646566696e65642062792065646963742d636f72652e6364646c20616e6420617373656d626c656420776974682074686973206c61777061636b0a3b20736368656d612e2049742069732061207075726520436f72652066756e6374696f6e20626f64792c206e6f7420616e206566666563742d63617061626c6520636f72652d626c6f636b2e0a0a73656d616e7469632d656666656374203d207b0a2020636f6f7264696e6174653a20747374722c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020696e707574547970653a20636f72652d747970652d7265662c2020202020202020202020202020203b20626f756e6465640a20206f7574707574547970653a20636f72652d747970652d7265662c20202020202020202020202020203b20626f756e6465640a2020657865637574696f6e436c6173733a202270726f6f664f6e6c7922202f202272756e74696d65222c2020203b206f7274686f676f6e616c20746f207772697465436c6173730a20206566666563744b696e6448696e743a206566666563742d6b696e642c0a2020666f6f747072696e744f626c69676174696f6e3a20747374722c0a2020636f73744f626c69676174696f6e3a20747374722c0a20206566666563744661696c757265733a207b202a206661696c7572652d6964656e74203d3e206566666563742d6661696c7572652d626f6479207d2c20203b206b6579656420627920636f6f7264696e6174653b20756e697175650a20206775617264537570706f72743a20626f6f6c2c0a7d0a0a6f62737472756374696f6e2d646566203d207b0a2020636f6f7264696e6174653a20747374722c0a2020617574686f72697479436c6173733a20617574686f726974792d636c6173732c0a20207061796c6f6164536368656d613a20636f72652d747970652d7265662c20202020202020202020203b2074797065642c20626f756e64656420286d617920626520656d707479207265636f7264290a7d0a0a3b206566666563742d6661696c7572652d626f64792c206566666563742d6b696e642c20617574686f726974792d636c6173732c20616e6420636f72652d747970652d7265662061726520646566696e65640a3b206f6e636520696e2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a3b202d2d2d2065646963742d6c61777061636b2d616461707465722e6364646c202d2d2d0a3b2065646963742d6c61777061636b2d616461707465722e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f72206f6e6520646972656374206465636c61726174697665206c61777061636b2074617267657420616461707465722e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a3b0a3b2054686520656e636c6f73696e67206c61777061636b206d616e69666573742073656c6563747320746865206578616374207461726765742070726f66696c652c207461726765742049522c0a3b20616e642061646170746572207265736f75726365206469676573742e2054686f7365206964656e74697469657320617265206e6f7420726570656174656420686572652e0a0a6c61777061636b2d61646170746572203d207b0a202061706956657273696f6e3a202265646963742e6c61777061636b2d616461707465722f7631222c0a2020636c6173733a20226465636c61726174697665222c0a20206f7065726174696f6e50726f66696c65733a207b0a202020202a2074737472203d3e206c61777061636b2d616461707465722d6f7065726174696f6e2d70726f66696c650a20207d2c0a2020656666656374496d706c656d656e746174696f6e733a207b0a202020202a2074737472203d3e206c61777061636b2d616461707465722d6566666563740a20207d2c0a2020627564676574733a207b0a202020202a2074737472203d3e206c61777061636b2d616461707465722d6275646765740a20207d2c0a7d0a0a3b204b657973206172652063616e6f6e6963616c206c61777061636b206f7065726174696f6e2d70726f66696c6520636f6f7264696e617465732e0a6c61777061636b2d616461707465722d6f7065726174696f6e2d70726f66696c65203d207b0a2020636f72653a20747374722c0a202073656d616e746963456666656374733a205b2b20747374725d2c0a7d0a0a3b204b657973206172652063616e6f6e6963616c206c61777061636b2073656d616e7469632d65666665637420636f6f7264696e617465732e20466f6f747072696e742c20636f73742c20616e640a3b206661696c757265206669656c6473206d7573742065786163746c792064697363686172676520746865206d61746368696e67206578706f72746564206566666563742e0a6c61777061636b2d616461707465722d656666656374203d207b0a2020746172676574496e7472696e7369633a20747374722c0a2020746172676574436f6e66696775726174696f6e3a207265736f757263652d7265662c0a20207772697465436c6173733a206c61777061636b2d616461707465722d77726974652d636c6173732c0a2020666f6f747072696e744f626c69676174696f6e3a20747374722c0a2020636f73744f626c69676174696f6e3a20747374722c0a20206661696c7572654d617070696e67733a207b202a206661696c7572652d6964656e74203d3e2074737472207d2c0a7d0a0a3b204b657973206172652063616e6f6e6963616c206578706f7274656420636f73742d6f626c69676174696f6e20636f6f7264696e617465732e0a6c61777061636b2d616461707465722d627564676574203d207b0a20206d617853746570733a2075696e742c0a20206d6178416c6c6f636174656442797465733a2075696e742c0a20206d61784f757470757442797465733a2075696e742c0a7d0a0a6c61777061636b2d616461707465722d77726974652d636c617373203d20226e6f6e6522202f20227265616422202f202263726561746522202f2022656e7375726522202f0a20202020202020202020202020202020202020202020202020202020202022617070656e6422202f20226d6f6469667922202f202264656c657465220a0a3b206661696c7572652d6964656e7420697320646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c2e0a0a3b202d2d2d2065646963742d7461726765742d70726f66696c652e6364646c202d2d2d0a3b2065646963742d7461726765742d70726f66696c652e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f7220746865204564696374207461726765742070726f66696c65206d616e69666573742e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76310a3b202873656520535045435f636f6e74696e75756d2d636f6e74726163742d62756e646c652d76312e6d64292e204a534f4e20696e207468652070726f736520737065637320697320610a3b207265766965772072656e646572696e672067656e6572617465642066726f6d207468697320736368656d613b2074686973204344444c206973207468652073696e676c6520736f757263650a3b206f66207472757468202845444943542d4142492d4e4f4455502d303031292e0a0a7461726765742d70726f66696c652d6d616e6966657374203d207b0a202061706956657273696f6e3a202265646963742e7461726765742d70726f66696c652f7631222c0a202069643a20747374722c202020202020202020202020202020202020202020202020203b20652e672e20226563686f2e64706f220a202076657273696f6e3a20747374722c20202020202020202020202020202020202020203b20652e672e202231220a20206163636570746564436f72654162693a205b2b20747374725d2c20202020202020203b20652e672e205b2265646963742e636f72652f7631225d0a0a2020696e7472696e736963733a207265736f757263652d7265662c0a2020696e7472696e7369634e616d6573706163653a20747374722c0a20203b207075626c697368657320746869732070726f66696c652773206f7065726174696f6e2d70726f66696c65207265636f72647320286f707469632074656d706c6174657320746861740a20203b206070726f66696c65602f60696d706c656d656e74736020636c6175736573207265736f6c766520616761696e7374292e205265666572656e63657320616e0a20203b206f7065726174696f6e2d70726f66696c65732d646f63756d656e74202845444943542d4142492d4f5050524f46494c452d534c4f542d303031292e0a20206f7065726174696f6e50726f66696c65733a207265736f757263652d7265662c0a2020666f6f747072696e74416c67656272613a207265736f757263652d7265662c0a2020636f7374416c67656272613a207265736f757263652d7265662c0a202074617267657449723a207265736f757263652d7265662c0a20206f62737472756374696f6e5461786f6e6f6d793a207265736f757263652d7265662c0a202076657269666965723a207265736f757263652d7265662c0a20206c6f77657265723a207265736f757263652d7265662c0a202073616e64626f783a207265736f757263652d7265662c0a20206675656c4d6f64656c3a207265736f757263652d7265662c0a0a20203b206669656c647320746865206c616e67756167652073706563207265717569726573206f662065766572792070726f66696c650a202062756e646c6550726f66696c653a207265736f757263652d7265662c0a202067656e657261746564417274696661637450726f66696c65733a205b2a207265736f757263652d7265665d2c0a202063616e6f6e6963616c456e636f64696e6752756c65733a207265736f757263652d7265662c0a20203b20412070726f66696c65207468617420616363657074732074686520646972656374206465636c61726174697665206c61777061636b2d6164617074657220414249206e616d65732069740a20203b2065786163746c79206f6e63652e2050726f66696c6573207468617420646f206e6f7420636f6e73756d65206c61777061636b206164617074657273206c6561766520746869730a20203b206f7074696f6e616c20736c6f7420616273656e74206f7220656d7074792e0a20203f2061636365707465644c61777061636b416461707465724162693a205b5d202f205b2265646963742e6c61777061636b2d616461707465722f7631225d2c0a2020646961676e6f737469634162693a207265736f757263652d7265662c0a0a20203b206170706c69636174696f6e20646f637472696e650a20206170706c69636174696f6e4d6f64656c3a202261746f6d6963222c0a202072656164436f6e73697374656e63793a20226170706c69636174696f6e2d736e617073686f7422202f20747374722c0a202067756172644576616c756174696f6e3a2022707265636f6d6d69742d61746f6d696322202f20747374722c0a20206f62737472756374696f6e526f6c6c6261636b3a20226e6f2d76697369626c652d6566666563747322202f20747374722c0a20206d756c74695461726765743a20626f6f6c2c0a20203b207768657468657220746865207461726765742063616e206576616c7561746520707265636f6d6d697420706f7374636f6e646974696f6e20286067756172616e746565602920636865636b730a20203b20696e73696465207468652061746f6d6963206170706c69636174696f6e20756e6974202845444943542d5441524745542d504f5354434f4e442d303031290a2020706f7374636f6e646974696f6e537570706f72743a20626f6f6c2c0a0a202064657465726d696e6973746963457865637574696f6e3a207265736f757263652d7265662c0a2020636f6e666f726d616e636546697874757265436f727075733a207265736f757263652d7265662c0a7d0a0a3b20536861726564207479706573207265736f757263652d72656620616e64207368613235362d6469676573742061726520646566696e6564206f6e636520696e0a3b2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d6120627920746865206275696c640a3b202845444943542d4142492d4e4f4455502d303031292e205468657920617265206e6f74207265646566696e656420686572652e0a0a3b202d2d2d20696e7472696e736963207369676e6174757265202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a3b20546865206172746966616374207265666572656e63656420627920746865206d616e696665737427732060696e7472696e7369637360207265736f757263652d726566206973207468650a3b20696e7472696e7369632d7369676e617475726520636f7270757320646f63756d656e742062656c6f772e20497473206c61796f757420697320666978656420736f2074776f0a3b20696e646570656e64656e742070726f66696c65732076616c69646174652f686173682074686520636f72707573206964656e746963616c6c790a3b202845444943542d4142492d494e5452494e534943532d444f432d303031292e0a0a3b20696e7472696e736963732069732061204d4150206b6579656420627920636f6f7264696e6174652c20736f2074686520736368656d6120697473656c6620656e666f726365730a3b20636f6f7264696e61746520756e697175656e6573732e20412070726f766964657220726563656976657320746865207265736f6c76656420636f7270757320617320610a3b206469676573742d626f756e642073656d616e74696320696e70757420616e64207265736f6c76657320636f6f7264696e617465732077697468696e20746861742061727469666163742e0a3b2045616368206d6170206b6579204d55535420657175616c20697473207265636f726427732060636f6f7264696e61746560206669656c640a3b202845444943542d4142492d494e5452494e5349432d554e495155452d303031292e0a696e7472696e736963732d646f63756d656e74203d207b0a202061706956657273696f6e3a202265646963742e7461726765742d70726f66696c652e696e7472696e736963732f7631222c0a2020696e7472696e736963733a207b202a2074737472203d3e20696e7472696e736963207d2c0a7d0a0a3b20546865206172746966616374207265666572656e63656420627920746865206d616e6966657374277320606f7065726174696f6e50726f66696c657360207265736f757263652d7265662e0a3b206f7065726174696f6e2d70726f66696c65202f206f707469632d74656d706c6174652061726520646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c2e204b657965642062790a3b20636f6f7264696e61746520736f207265736f6c7574696f6e2063616e2774207069636b206265747765656e2074776f2073616d652d636f6f7264696e6174652070726f66696c65730a3b202845444943542d4142492d4f5050524f46494c452d534c4f542d3030312c2045444943542d4142492d4f5050524f46494c452d554e495155452d303031292e0a6f7065726174696f6e2d70726f66696c65732d646f63756d656e74203d207b0a202061706956657273696f6e3a202265646963742e7461726765742d70726f66696c652e6f7065726174696f6e2d70726f66696c65732f7631222c0a202070726f66696c65733a207b202a2074737472203d3e206f7065726174696f6e2d70726f66696c65207d2c0a7d0a0a3b2041207479706564207072652d6c6f776572696e67207175657374696f6e20746861742063616e2062652070726f706f73656420627920576174736f6e206f7220616e206167656e7420616e640a3b20636865636b65642062792074686520636f6d70696c65722e2049742069732063616e6f6e6963616c2d43424f5220656e636f64656420756e6465720a3b206065646963742e6c6f776572696e672d726571756972656d656e74732f7631603b2074686520636f6d70696c657220636865636b7320746869732061727469666163742c206e6f74207468650a3b2070726f736520746861742070726f64756365642069742e0a6c6f776572696e672d726571756972656d656e7473203d207b0a202061706956657273696f6e3a202265646963742e6c6f776572696e672d726571756972656d656e74732f7631222c0a20206f7065726174696f6e50726f66696c653a20747374722c0a202073656d616e746963456666656374733a205b2a2073656d616e7469632d6566666563742d726571756972656d656e745d2c0a202072657175697265645772697465436c61737365733a205b2a2077726974652d636c6173735d2c0a202067756172644b696e64733a205b2a2067756172642d6b696e645d2c0a202061746f6d69636974793a2061746f6d69636974792d726571756972656d656e742c0a2020706f7374636f6e646974696f6e537570706f72743a20626f6f6c2c0a20206f62737472756374696f6e436f6f7264696e617465733a205b2a20747374725d2c0a2020666f6f747072696e744f626c69676174696f6e733a205b2a20747374725d2c0a2020636f73744f626c69676174696f6e733a205b2a20747374725d2c0a20206f70746963436f6e74726163743a20747374722c0a7d0a0a73656d616e7469632d6566666563742d726571756972656d656e74203d207b0a2020636f6f7264696e6174653a20747374722c0a20207772697465436c6173733a2077726974652d636c6173732c0a202067756172644b696e64733a205b2a2067756172642d6b696e645d2c0a20206f62737472756374696f6e436f6f7264696e617465733a205b2a20747374725d2c0a2020666f6f747072696e744f626c69676174696f6e733a205b2a20747374725d2c0a2020636f73744f626c69676174696f6e733a205b2a20747374725d2c0a7d0a0a77726974652d636c617373203d20226e6f6e6522202f20227265616422202f202263726561746522202f2022656e7375726522202f2022617070656e6422202f0a2020202020202020202020202020227265706c61636522202f202264656c65746522202f20747374720a67756172642d6b696e64203d2022707265636f6d6d69742d61746f6d696322202f20747374720a61746f6d69636974792d726571756972656d656e74203d202261746f6d696322202f20747374720a0a3b20412067656e75696e6520756e696f6e3a207075726520636f6e7374727563746f7273206361727279206e6f20656666656374206b696e64206f72206661696c757265733b206566666563740a3b20696e7472696e73696373206d757374202845444943542d5441524745542d494e5452494e5349432d434c4153532d303031292e2054686520736368656d6120656e666f7263657320746869732c0a3b206e6f74206120636f6d6d656e742e0a0a3b2054686520696e7472696e736963277320636f6f7264696e6174652069732074686520696e7472696e73696373206d6170204b45592c206e6f7420612076616c7565206669656c642c20736f207468650a3b206b657920616e6420636f6f7264696e6174652063616e206e65766572206469736167726565202845444943542d4142492d494e5452494e5349432d554e495155452d303031292e0a696e7472696e736963203d20707572652d696e7472696e736963202f206566666563742d696e7472696e7369630a0a707572652d696e7472696e736963203d207b0a2020696e7472696e736963436c6173733a202270757265222c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020617267756d656e7454797065733a205b2a20636f72652d747970652d7265665d2c0a202072657475726e547970653a20636f72652d747970652d7265662c0a20206775617264537570706f72743a2066616c73652c0a2020666f6f747072696e7454656d706c6174653a20747374722c0a2020636f737454656d706c6174653a20747374722c0a20207772697465436c6173733a20226e6f6e65222c0a7d0a0a6566666563742d696e7472696e736963203d207b0a2020696e7472696e736963436c6173733a2022656666656374222c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020617267756d656e7454797065733a205b2a20636f72652d747970652d7265665d2c0a202072657475726e547970653a20636f72652d747970652d7265662c0a20206566666563744b696e643a206566666563742d6b696e642c0a20203b206d6170206b65796564206279206661696c75726520636f6f7264696e61746520286661696c7572652d6964656e74293b20746865206661696c75726520636f6f7264696e6174652069730a20203b20746865206b65792c206e6f7420612076616c7565206669656c642c20736f20756e697175656e657373206973207374727563747572616c0a20203b202845444943542d4142492d4641494c5552452d554e495155452d303031292e0a20206566666563744661696c757265733a207b202a206661696c7572652d6964656e74203d3e206566666563742d6661696c7572652d626f6479207d2c0a20206775617264537570706f72743a20626f6f6c2c0a2020666f6f747072696e7454656d706c6174653a20747374722c0a2020636f737454656d706c6174653a20747374722c0a20207772697465436c6173733a20227265616422202f202263726561746522202f2022656e7375726522202f2022617070656e6422202f20227265706c61636522202f0a20202020202020202020202020202264656c65746522202f2022637573746f6d222c0a202063616e5061727469636970617465496e41746f6d696347756172643a20626f6f6c2c0a7d0a0a3b206566666563742d6661696c7572652d626f64792c206566666563742d6b696e642c20617574686f726974792d636c6173732c20616e6420636f72652d747970652d7265662061726520646566696e65640a3b206f6e636520696e2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a3b202d2d2d2065646963742d617574686f726974792d66616374732e6364646c202d2d2d0a3b2065646963742d617574686f726974792d66616374732e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f722074686520666972737420636f6d70696c65722d636f6e7465787420617574686f726974792d666163747320646f63756d656e742e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a3b0a3b205468697320736368656d6120697320617373656d626c656420776974682065646963742d636f6d6d6f6e2e6364646c20736f20736f757263652e6469676573742075736573207468650a3b20736861726564207368613235362d6469676573742074797065642076616c75652e204a534f4e2069732061207265766965772f696e7075742072656e646572696e673a206974730a3b20607368613235363a3c3634206865783e6020736f75726365206469676573742069732070726f6a656374656420746f205b60736861323536602c203332207261772062797465735d206f6e0a3b2074686520776972652c20616e64206974732066616374206172726179732070726f6a65637420746f2074686520636f6f7264696e6174652d6b65796564206d6170732062656c6f772e0a0a617574686f726974792d6661637473203d207b0a202061706956657273696f6e3a202265646963742e617574686f726974792d66616374732f7631222c0a2020736f757263653a20617574686f726974792d666163742d736f757263652c0a20206f7065726174696f6e50726f66696c65733a207b202a2074737472203d3e20617574686f726974792d6f7065726174696f6e2d70726f66696c652d66616374207d2c0a20206566666563745772697465436c61737365733a207b202a2074737472203d3e20617574686f726974792d77726974652d636c617373207d2c0a2020627564676574733a207b202a2074737472203d3e20617574686f726974792d6275646765742d66616374207d2c0a7d0a0a617574686f726974792d666163742d736f75726365203d207b0a20206b696e643a20226c61777061636b22202f202274617267657450726f66696c65222c0a2020636f6f7264696e6174653a20747374722c0a20206469676573743a207368613235362d6469676573742c0a7d0a0a3b20546865206d6170206b65792069732074686520736f75726365206f7065726174696f6e2d70726f66696c6520636f6f7264696e6174652e204974206973206e6f7420726570656174656420696e0a3b207468652076616c75652c20736f2061206b657920616e6420656d62656464656420636f6f7264696e6174652063616e6e6f742064697361677265652e20416c6c6f7765642077726974650a3b20636c61737365732061726520612063616e6f6e6963616c206d61702d7365743a2074686520636c6173732069732074686520756e69717565206b657920616e64206e756c6c206973207468650a3b20756e6974206d61726b65722e2043616e6f6e6963616c2043424f52206669786573206b6579206f7264657220776974686f75742061207365636f6e64206f72646572696e672072756c652e0a617574686f726974792d6f7065726174696f6e2d70726f66696c652d66616374203d207b0a2020636f72653a20747374722c0a2020616c6c6f7765645772697465436c61737365733a207b202a20617574686f726974792d77726974652d636c617373203d3e206e756c6c207d2c0a7d0a0a3b20546865206566666563745772697465436c6173736573206d6170206b6579206973207468652073656d616e7469632065666665637420636f6f7264696e6174652e2054686520627564676574730a3b206d6170206b65792069732074686520736f757263652062756467657420636f6f7264696e6174652e2043616e6f6e6963616c2043424f52206d61702d6b657920756e697175656e6573730a3b206d616b6573206475706c6963617465206661637420636f6f7264696e61746573207374727563747572616c6c7920756e726570726573656e7461626c652e0a617574686f726974792d6275646765742d66616374203d207b0a20206d617853746570733a2075696e742c0a20206d6178416c6c6f636174656442797465733a2075696e742c0a20206d61784f757470757442797465733a2075696e742c0a7d0a0a3b20417574686f726974794661637473446f63756d656e7420763120696e74656e74696f6e616c6c792061636365707473206f6e6c792074686520777269746520636c6173736573207468650a3b2063757272656e7420636f6d70696c6572206d6f64656c2063616e20636f6e73756d652e2060637573746f6d602069732074686520736f6c6520763120637573746f6d207370656c6c696e673b0a3b20617262697472617279207461726765742d70726f66696c6520657874656e73696f6e20737472696e677320646f206e6f7420656e746572207468697320636f6d70696c657220706174682e0a617574686f726974792d77726974652d636c617373203d20226e6f6e6522202f20227265616422202f202263726561746522202f2022656e7375726522202f2022617070656e6422202f0a202020202020202020202020202020202020202020202020227265706c61636522202f202264656c65746522202f2022637573746f6d220a0a3b202d2d2d2065646963742d7461726765742d69722e6364646c202d2d2d0a3b20535044582d4c6963656e73652d4964656e7469666965723a204170616368652d322e300a3b2065646963742d7461726765742d69722e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f72207468652045646963742d6f776e65642054617267657420495220617274696661637420656e76656c6f70652e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a3b0a3b205468697320736368656d6120697320617373656d626c656420776974682065646963742d636f6d6d6f6e2e6364646c20616e642065646963742d636f72652e6364646c2e2049740a3b2064656c696265726174656c792072657573657320436f72652065787072657373696f6e732c20707265646963617465732c20627564676574732c206c6f63616c207265666572656e6365732c0a3b206f62737472756374696f6e20726561736f6e732c20616e64206f62737472756374696f6e2061726d7320736f2074686520736368656d61206d617463686573207468652076616c75650a3b20656d6974746564206279207468652063616e6f6e6963616c2054617267657420495220656e636f64657220726174686572207468616e20726573746174696e672074686f73652074797065732e0a3b2049742064657363726962657320746865207374727563747572616c207368617065206f662076616c6964206c6f776572696e672d70726f6475636564206172746966616374732e205468650a3b206c6f776572696e6720616e6420656e636f64657220636f6e7472616374732073657061726174656c7920656e666f7263652073656d616e746963206964656e7469666965722072756c65730a3b20616e642063616e6f6e6963616c206f72646572696e672f64656475706c69636174696f6e20666f72207365742d6c696b652076616c7565732e0a0a3b2054617267657420495220656e636f64696e672072656a6563747320616e20656d707479207461726765742d70726f66696c6520636f6f7264696e617465206265666f72652062797465730a3b2065786973742c20736f207468697320726f6f74207469676874656e732074686520736861726564207374727563747572616c207265736f757263652d726566206163636f7264696e676c792e0a7461726765742d69722d7265736f757263652d726566203d207b0a202069643a2074737472202e7265676578702022283f73292e2b222c0a20206469676573743a207368613235362d6469676573742c0a7d0a0a7461726765742d69722d6172746966616374203d207461726765742d69722d636c6f7365642d6172746966616374202f207461726765742d69722d6c65676163792d61727469666163740a0a7461726765742d69722d61727469666163742d636f6d6d6f6e203d20280a20206b696e643a202274617267657449724172746966616374222c0a2020646f6d61696e3a20747374722c0a202074617267657450726f66696c653a207461726765742d69722d7265736f757263652d7265662c0a2020736f75726365436f7265436f6f7264696e6174653a2074737472202e7265676578702022283f73292e2b222c0a290a0a7461726765742d69722d636c6f7365642d6172746966616374203d207b0a20207461726765742d69722d61727469666163742d636f6d6d6f6e2c0a202073656d616e746963436c6f737572653a207461726765742d69722d73656d616e7469632d636c6f737572652c0a2020696e74656e74733a207b202a2074737472203d3e207461726765742d69722d696e74656e74207d2c0a7d0a0a7461726765742d69722d6c65676163792d6172746966616374203d207b0a20207461726765742d69722d61727469666163742d636f6d6d6f6e2c0a2020696e74656e74733a207b202a2074737472203d3e207461726765742d69722d6c65676163792d696e74656e74207d2c0a7d0a0a7461726765742d69722d73656d616e7469632d636c6f73757265203d207b0a2020736f75726365436f72653a207461726765742d69722d7265736f757263652d7265662c0a20206c61777061636b733a205b2a207461726765742d69722d7265736f757263652d7265665d2c0a7d0a0a7461726765742d69722d696e74656e74203d207b0a20207461726765742d69722d696e74656e742d636f6d6d6f6e2c0a20203f2062617369733a20636f72652d657870722c0a7d0a0a7461726765742d69722d6c65676163792d696e74656e74203d207b0a20207461726765742d69722d696e74656e742d636f6d6d6f6e2c0a7d0a0a7461726765742d69722d696e74656e742d636f6d6d6f6e203d20280a20206f7065726174696f6e50726f66696c653a20747374722c0a2020696e707574436f6e73747261696e74733a205b2a20696e7075742d636f6e73747261696e745d2c0a2020636f72654576616c756174696f6e4275646765743a20636f72652d6275646765742c0a2020726571756972656d656e74733a205b2a207461726765742d69722d726571756972656d656e745d2c0a202073746570733a205b2a207461726765742d69722d737465705d2c0a2020726573756c743a20636f72652d657870722c0a290a0a7461726765742d69722d726571756972656d656e74203d207b0a202069643a20747374722c0a20207072656469636174653a20636f72652d7072656469636174652c0a20206f6e4661696c7572653a20726571756972652d6661696c7572652d61726d2c0a7d0a0a7461726765742d69722d73746570203d207b0a202069643a20747374722c0a202062696e64696e673a206c6f63616c2d7265662c0a20206566666563743a20747374722c0a2020746172676574496e7472696e7369633a20747374722c0a2020696e7075743a20636f72652d657870722c0a20206f62737472756374696f6e4661696c757265733a205b2a206661696c7572652d6964656e745d2c0a20206f62737472756374696f6e41726d733a207b202a206661696c7572652d6964656e74203d3e206f62737472756374696f6e2d61726d207d2c0a7d0a", - "rawSha256": "a5d5ea82a9e64aa78c4a44204d3e8919c1c590febb967f1d31639fdc2a20a96c" + "bytesHex": "3b20535044582d4c6963656e73652d4964656e7469666965723a204170616368652d322e300a3b2065646963742d70726f76696465722d636f6e7472616374732e6364646c0a3b2047656e6572617465642066726f6d2045646963742d6f776e65642041424920667261676d656e74732e20444f204e4f5420454449542e0a0a3b202d2d2d2065646963742d636f6d6d6f6e2e6364646c202d2d2d0a3b2065646963742d636f6d6d6f6e2e6364646c0a3b20536861726564204344444c20747970657320666f722074686520456469637420414249732c20646566696e6564204f4e4345206865726520736f20746865792063616e6e6f742064726966740a3b202845444943542d4142492d4e4f4455502d303031292e2054776f2067726f7570733a0a3b2020202d207265736f757263652d7265662c207368613235362d6469676573742c206566666563742d6661696c7572652d626f64792c206566666563742d6b696e642c20617574686f726974792d636c6173732c0a3b2020202020636f72652d747970652d7265663a20617373656d626c656420776974682065646963742d7461726765742d70726f66696c652e6364646c20616e640a3b202020202065646963742d6c61777061636b2e6364646c20627920746865206275696c643b2074686f736520736368656d617320646f206e6f74207265646566696e65207468656d2e0a3b2020202d206f7065726174696f6e2d70726f66696c652c206f707469632d74656d706c6174652c2061706572747572652d726571756972656d656e7420616e6420746865697220726566733a0a3b2020202020636f6e73756d65642062792074686520436f72652f6f70746963206c61796572202865646963742d636f72652e6364646c2920616e64207265666572656e636564206279207468650a3b20202020206c616e67756167652f7461726765742d70726f66696c652073706563732e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a0a3b2041206e6f726d617469766520737562636f6d706f6e656e74207265666572656e636564206279206964656e7469747920706c7573206469676573742e204d616e696665737473206e657665720a3b20656d626564207468656972206f776e2073656c662d64696765737420696e20746865697220707265696d616765202845444943542d434f52452d53454c46484153482d303031292e0a7265736f757263652d726566203d207b2069643a20747374722c206469676573743a207368613235362d646967657374207d0a0a3b20446967657374732061726520617574686f726974617469766520617320747970656420627974652076616c7565732c206e657665722068657820737472696e67732e20526576696577204a534f4e0a3b2072656e64657273207468697320617320227368613235363a3c3634206c6f77657263617365206865783e22202845444943542d4449474553542d574952452d303031292e0a7368613235362d646967657374203d205b20616c676f726974686d3a2022736861323536222c2062797465733a2062737472202e73697a65203332205d0a0a3b2041206e616d6564206c6f772d6c6576656c206661696c75726520616e206566666563742063616e2072616973652e2054686520736f75726365206f62737472756374696f6e206d61700a3b2062696e64732069742028627920636f6f7264696e6174652920616e6420636f6e73747275637473206120747970656420646f6d61696e206f62737472756374696f6e2066726f6d206974730a3b207061796c6f6164202845444943542d4142492d4641494c5552452d4e414d45442d303031292e0a3b20416e20656666656374277320606566666563744661696c7572657360206c697374204d555354206861766520756e697175652060636f6f7264696e61746560733a2073696e6365207468650a3b206f62737472756374696f6e206d6170206973206b6579656420627920636f6f7264696e6174652c2074776f206661696c757265732073686172696e67206120636f6f7264696e61746520286576656e0a3b207769746820646966666572656e7420617574686f72697479436c6173732f7061796c6f61645479706529206d616b652065786861757374697665206d617070696e6720616e642062696e6465720a3b20747970696e6720616d626967756f757320616e64206172652072656a6563746564202845444943542d4142492d4641494c5552452d554e495155452d303031292e0a3b0a3b2045666665637473206361727279207468656972206661696c757265732061732061206d617020607b206661696c7572652d6964656e74203d3e206566666563742d6661696c7572652d626f6479207d600a3b202873656520746865207461726765742f6c61777061636b2065666665637420736368656d6173292e20546865206661696c75726520636f6f7264696e61746520697320746865206d61700a3b204b45592c20736f206974206973206e6f7420726570656174656420696e2074686520626f647920616e642063616e6e6f74206469736167726565207769746820746865206b65792e0a6566666563742d6661696c7572652d626f6479203d207b0a2020617574686f72697479436c6173733a20617574686f726974792d636c6173732c0a20207061796c6f6164547970653a20636f72652d747970652d7265662c202020202020202020202020203b2074797065642c20626f756e64656420286d617920626520656d707479207265636f7264290a7d0a0a3b2041206661696c75726520636f6f7264696e617465206d7573742062652061206261726520456469637420606964656e746020286c65747465722f756e64657273636f7265207468656e0a3b206c6574746572732f6469676974732f756e64657273636f7265732920414e44206d757374206e6f742062652061207265736572766564206b6579776f72642028652e672e2060656c7365602c0a3b20606261736973602c20607768657265602c206072657175697265602c2060666f72602c2060696660292e2054686520736f75726365206f62737472756374696f6e2d6d6170204c4853206f6e6c790a3b20616363657074732061206e6f6e2d6b6579776f726420606964656e74602c20736f20612068797068656e2f646f742f6b6579776f726420636f6f7264696e61746520776f756c642062650a3b204142492d76616c69642079657420696d706f737369626c6520746f206d617020657868617573746976656c7920696e20736f757263652e20546865207265676578206361707475726573207468650a3b206c65786963616c2073686170653b206b6579776f7264206578636c7573696f6e20697320616e206164646974696f6e616c2076616c69646174696f6e2072756c650a3b202845444943542d4142492d4641494c5552452d4944454e542d303031292e0a6661696c7572652d6964656e74203d2074737472202e72656765787020225b412d5a612d7a5f5d5b412d5a612d7a302d395f5d2a220a0a6566666563742d6b696e64203d20227265616422202f202263726561746522202f2022656e7375726522202f20227265706c61636522202f202264656c65746522202f0a202020202020202020202020202022617070656e6422202f202272656475636522202f202273656d616e7469632e656d697422202f2022637573746f6d220a0a617574686f726974792d636c617373203d2022646f6d61696e4d61707061626c6522202f20227061727469636970616e744f776e656422202f2022696e746567726974794661756c7422202f0a202020202020202020202020202020202020227265736f757263654661756c7422202f2022696e7465726e616c4661756c74220a0a636f72652d747970652d726566203d20747374722020203b2063616e6f6e6963616c20436f7265207479706520636f6f7264696e6174650a0a3b20416e206f7065726174696f6e2070726f66696c6520737570706c69657320746865206f707469632074656d706c617465206120436f726520696e74656e74207265736f6c766573206974730a3b206f707469634b696e642f626f756e646172794b696e642f737570706f7274506f6c6963792f6c6f7373446973706f736974696f6e2066726f6d2e205461726765742070726f66696c657320616e640a3b206c61777061636b73207075626c6973682074686573652061732061206d617020607b20636f6f7264696e617465203d3e206f7065726174696f6e2d70726f66696c65207d602c20736f207468650a3b20636f6f7264696e61746520697320746865204b45592c206e6f7420612076616c7565206669656c64202845444943542d4f505449432d54454d504c4154452d4f574e45522d3030312c0a3b2045444943542d4142492d4f5050524f46494c452d554e495155452d303031292e0a6f7065726174696f6e2d70726f66696c65203d207b0a20206f7074696354656d706c6174653a206f707469632d74656d706c6174652c0a20206566666563745072656469636174653a20747374722c20202020202020202020203b20636f6f7264696e617465206f6620746865206f7065726174696f6e2d6d6f6465207072656469636174650a7d0a0a6f707469632d74656d706c617465203d207b0a20206f707469634b696e643a2022726576656c6174696f6e22202f20226166666563745265696e746567726174696f6e222c0a2020626f756e646172794b696e643a202270726f6a656374696f6e22202f2022616666656374222c0a2020737570706f7274506f6c6963793a20747374722c202020202020202020202020203b2063616e6f6e6963616c20737570706f72742d706f6c69637920636f6f7264696e6174650a20206c6f7373446973706f736974696f6e3a20747374722c20202020202020202020203b2063616e6f6e6963616c206c6f73732d646973706f736974696f6e20636f6f7264696e6174650a20203f20626173697354656d706c6174653a20747374722c20202020202020202020203b206f7074696f6e616c206469676573742d6c6f636b65642062617369732074656d706c61746520636f6f72640a20203b2074686520617065727475726520726571756972656d656e7420746869732074656d706c61746520737570706c6965732e205265717569726564207768656e207468652074656d706c6174650a20203b2069732074686520736f75726365206f66206120436f7265206f707469632773206170657274757265526571756972656d656e742028692e652e2074686520696e74656e7420686173206e6f0a20203b20736f757263652060666f6f747072696e74203c3d202e2e2e60292c2073696e6365206170657274757265526571756972656d656e74206973206d616e6461746f727920696e20436f72650a20203b202845444943542d4f505449432d41504552545552452d5245462d303031292e0a20203f206170657274757265526571756972656d656e743a2061706572747572652d726571756972656d656e742c0a7d0a0a3b206170657274757265526571756972656d656e742069732061207479706564207265666572656e63652c206e65766572206120667265652d666f726d20737472696e672e2041207265766965770a3b2072656e646572696e67206d61792073686f772069747320636f6f7264696e617465202845444943542d4f505449432d41504552545552452d5245462d303031292e0a61706572747572652d726571756972656d656e74203d20666f6f747072696e742d6365696c696e672d726566202f2061627374726163742d666f6f747072696e742d6f626c69676174696f6e2d7265660a666f6f747072696e742d6365696c696e672d726566203d207b206b696e643a2022666f6f747072696e744365696c696e67222c207265663a2074737472207d0a61627374726163742d666f6f747072696e742d6f626c69676174696f6e2d726566203d207b206b696e643a20226162737472616374466f6f747072696e744f626c69676174696f6e222c207265663a2074737472207d0a0a3b202d2d2d2065646963742d636f72652e6364646c202d2d2d0a3b2065646963742d636f72652e6364646c0a3b204e6f726d617469766520736368656d6120666f722074686520456469637420436f72652076312073656d616e746963206d6f64656c2e0a3b0a3b2053636f706520626f756e646172793a20746869732066696c6520646566696e657320436f7265206d65616e696e6720616e6420736368656d61207368617065206f6e6c792e20497420646f65730a3b206e6f7420646566696e6520612063616e6f6e6963616c20656e636f6465722c20436f7265206d6f64756c652068617368206669656c64732c20686173682066697874757265732c207461726765740a3b206c6f776572696e672c2061646d697373696f6e2062756e646c65732c206f72207461726765742d6f776e65642049522e0a0a636f72652d6d6f64756c65203d207b0a202061706956657273696f6e3a202265646963742e636f72652f7631222c0a2020636f6f7264696e6174653a20747374722c0a2020696d706f7274733a205b2a20636f72652d696d706f72745d2c0a202074797065733a207b202a2074737472203d3e20636f72652d74797065207d2c0a2020696e74656e74733a207b202b2074737472203d3e20636f72652d696e74656e74207d2c0a20207265717569726564436f72654361706162696c69746965733a205b2a20747374725d2c0a7d0a0a636f72652d696d706f7274203d207b0a20206b696e643a20226c61777061636b22202f202274617267657422202f2022636f7265222c0a20207265663a207265736f757263652d7265662c0a20203f20616c6961733a20747374722c0a7d0a0a3b202d2d2d207479706573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a636f72652d74797065203d20636f72652d7363616c61722d74797065202f20636f72652d7265636f72642d74797065202f20636f72652d76617269616e742d74797065202f0a202020202020202020202020636f72652d6f7074696f6e2d74797065202f20636f72652d6c6973742d74797065202f20636f72652d6d61702d74797065202f0a202020202020202020202020636f72652d6361706162696c6974792d7265662d747970650a0a636f72652d7363616c61722d74797065203d20636f72652d626f6f6c2d74797065202f20636f72652d696e742d74797065202f20636f72652d737472696e672d74797065202f0a20202020202020202020202020202020202020636f72652d62797465732d74797065202f20636f72652d756e69742d747970650a0a636f72652d626f6f6c2d74797065203d207b206b696e643a2022426f6f6c22207d0a636f72652d756e69742d74797065203d207b206b696e643a2022556e697422207d0a636f72652d696e742d74797065203d207b0a20206b696e643a202249363422202f202255363422202f202249333222202f202255333222202f202249313622202f202255313622202f2022493822202f20225538222c0a7d0a636f72652d737472696e672d74797065203d207b0a20206b696e643a2022537472696e67222c0a20206d61783a2075696e742c0a202063616e6f6e6963616c3a2022756e69636f64652d7363616c61722d6e666322202f20227261772d75746638222c0a7d0a636f72652d62797465732d74797065203d207b0a20206b696e643a20224279746573222c0a20206d61783a2075696e742c0a7d0a636f72652d7265636f72642d74797065203d207b0a20206b696e643a20225265636f7264222c0a20206669656c64733a207b202a2074737472203d3e20636f72652d747970652d726566207d2c0a7d0a636f72652d76617269616e742d74797065203d207b0a20206b696e643a202256617269616e74222c0a202063617365733a207b202b2074737472203d3e2076617269616e742d636173652d626f6479207d2c0a7d0a76617269616e742d636173652d626f6479203d207b0a20203f207061796c6f61643a20636f72652d747970652d7265662c0a7d0a636f72652d6f7074696f6e2d74797065203d207b0a20206b696e643a20224f7074696f6e222c0a20206974656d3a20636f72652d747970652d7265662c0a7d0a636f72652d6c6973742d74797065203d207b0a20206b696e643a20224c697374222c0a20206974656d3a20636f72652d747970652d7265662c0a20206d61783a2075696e742c0a7d0a636f72652d6d61702d74797065203d207b0a20206b696e643a20224d6170222c0a20206b65793a20636f72652d747970652d7265662c0a202076616c75653a20636f72652d747970652d7265662c0a20206d61783a2075696e742c0a7d0a636f72652d6361706162696c6974792d7265662d74797065203d207b0a20206b696e643a20224361706162696c697479526566222c0a20206974656d3a20636f72652d747970652d7265662c0a7d0a0a3b20636f72652d747970652d72656620697320646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d612e0a0a3b202d2d2d207265666572656e63657320616e642076616c756573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a3b204c6f63616c206964656e7469747920697320616c7068612d737461626c652e20606964602069732074686520636f6d70696c65722d6f776e6564206c6f63616c20636f6f7264696e6174653b0a3b2060616c7068614e616d656020697320746865206e6f726d616c697a65642068756d616e2f6465627567206e616d652e20536f757263652062696e646572207370656c6c696e67206973206e6f740a3b206964656e746974792e0a6c6f63616c2d726566203d207b0a202069643a20747374722c0a2020616c7068614e616d653a20747374722c0a2020747970653a20636f72652d747970652d7265662c0a7d0a0a636f72652d76616c7565203d20636f72652d6e756c6c2d76616c7565202f20636f72652d626f6f6c2d76616c7565202f20636f72652d696e742d76616c7565202f0a20202020202020202020202020636f72652d737472696e672d76616c7565202f20636f72652d62797465732d76616c7565202f20636f72652d7265636f72642d76616c7565202f0a20202020202020202020202020636f72652d76617269616e742d76616c7565202f20636f72652d6c6973742d76616c7565202f20636f72652d6d61702d76616c7565202f0a20202020202020202020202020636f72652d6361706162696c6974792d76616c75650a0a636f72652d6e756c6c2d76616c7565203d207b206b696e643a20226e756c6c22207d0a636f72652d626f6f6c2d76616c7565203d207b206b696e643a2022626f6f6c222c2076616c75653a20626f6f6c207d0a636f72652d696e742d76616c7565203d207b206b696e643a2022696e74222c2077696474683a20747374722c2076616c75653a20696e74207d0a636f72652d737472696e672d76616c7565203d207b206b696e643a2022737472696e67222c2076616c75653a2074737472207d0a636f72652d62797465732d76616c7565203d207b206b696e643a20226279746573222c2076616c75653a2062737472207d0a636f72652d7265636f72642d76616c7565203d207b206b696e643a20227265636f7264222c206669656c64733a207b202a2074737472203d3e20636f72652d76616c7565207d207d0a636f72652d76617269616e742d76616c7565203d207b0a20206b696e643a202276617269616e74222c0a2020747970653a20636f72652d747970652d7265662c0a2020636173653a20747374722c0a20203f207061796c6f61643a20636f72652d76616c75652c0a7d0a636f72652d6c6973742d76616c7565203d207b206b696e643a20226c697374222c2076616c7565733a205b2a20636f72652d76616c75655d207d0a636f72652d6d61702d76616c7565203d207b206b696e643a20226d6170222c20656e74726965733a205b2a205b6b65793a20636f72652d76616c75652c2076616c75653a20636f72652d76616c75655d5d207d0a636f72652d6361706162696c6974792d76616c7565203d207b0a20206b696e643a20226361706162696c697479222c0a2020726563656970743a207368613235362d6469676573742c0a7d0a0a3b2045646963742d617574686f72656420707572652068656c70657273207573652061207075726520436f72652066756e6374696f6e20626f64792e2054686520626f64792063616e2062696e640a3b20707572652065787072657373696f6e7320616e642072657475726e20616e2065787072657373696f6e2c206275742069742063616e6e6f7420636f6e7461696e20436f7265206566666563742c0a3b2067756172642c206272616e63682c206c6f6f702c206d617463682d6e6f64652c206f722070726f6f662d6f626c69676174696f6e206e6f6465732e0a636f72652d666e2d626f6479203d207b0a2020706172616d733a205b2a206c6f63616c2d7265665d2c0a2020626f64793a20636f72652d707572652d626c6f636b2c0a7d0a0a636f72652d707572652d626c6f636b203d207b0a20206c6f63616c733a205b2a206c6f63616c2d7265665d2c0a202062696e64696e67733a205b2a20707572652d6c65742d6e6f64655d2c0a2020726573756c743a20636f72652d657870722c0a7d0a0a707572652d6c65742d6e6f6465203d207b0a20206b696e643a20226c6574222c0a202062696e64696e673a206c6f63616c2d7265662c0a202076616c75653a20636f72652d657870722c0a7d0a0a3b202d2d2d2065787072657373696f6e7320616e642070726564696361746573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a636f72652d65787072203d206c6f63616c2d65787072202f20636f6e73742d65787072202f207265636f72642d65787072202f206669656c642d65787072202f0a20202020202020202020202076617269616e742d65787072202f206d617463682d65787072202f2063616c6c2d65787072202f206c6973742d65787072202f206d61702d65787072202f0a20202020202020202020202069662d657870720a0a6c6f63616c2d65787072203d207b206b696e643a20226c6f63616c222c207265663a206c6f63616c2d726566207d0a636f6e73742d65787072203d207b206b696e643a2022636f6e7374222c2076616c75653a20636f72652d76616c7565207d0a7265636f72642d65787072203d207b206b696e643a20227265636f7264222c206669656c64733a207b202a2074737472203d3e20636f72652d65787072207d207d0a6669656c642d65787072203d207b206b696e643a20226669656c64222c20626173653a20636f72652d657870722c206669656c643a2074737472207d0a76617269616e742d65787072203d207b0a20206b696e643a202276617269616e74222c0a2020747970653a20636f72652d747970652d7265662c0a2020636173653a20747374722c0a20203f207061796c6f61643a20636f72652d657870722c0a7d0a6d617463682d65787072203d207b0a20206b696e643a20226d61746368222c0a20207363727574696e65653a20636f72652d657870722c0a202061726d733a205b2b206d617463682d61726d5d2c0a7d0a6d617463682d61726d203d207b0a2020636173653a20747374722c0a20203f2062696e6465723a206c6f63616c2d7265662c0a2020626f64793a20636f72652d657870722c0a7d0a63616c6c2d65787072203d207b0a20206b696e643a202263616c6c222c0a202063616c6c65653a20747374722c0a202074797065417267733a205b2a20636f72652d747970652d7265665d2c0a2020617267733a205b2a20636f72652d657870725d2c0a7d0a6c6973742d65787072203d207b206b696e643a20226c697374222c2076616c7565733a205b2a20636f72652d657870725d207d0a6d61702d65787072203d207b206b696e643a20226d6170222c20656e74726965733a205b2a205b6b65793a20636f72652d657870722c2076616c75653a20636f72652d657870725d5d207d0a69662d65787072203d207b0a20206b696e643a20226966222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20207468656e3a20636f72652d657870722c0a2020656c73653a20636f72652d657870722c0a7d0a0a636f72652d707265646963617465203d20747275652d707265646963617465202f2066616c73652d707265646963617465202f206e6f742d707265646963617465202f0a2020202020202020202020202020202020616c6c2d707265646963617465202f20616e792d707265646963617465202f20636f6d706172652d707265646963617465202f0a202020202020202020202020202020202063616c6c2d707265646963617465202f206f62737472756374696f6e2d7072656469636174650a0a747275652d707265646963617465203d207b206b696e643a20227472756522207d0a66616c73652d707265646963617465203d207b206b696e643a202266616c736522207d0a6e6f742d707265646963617465203d207b206b696e643a20226e6f74222c2076616c75653a20636f72652d707265646963617465207d0a616c6c2d707265646963617465203d207b206b696e643a2022616c6c222c2076616c7565733a205b2b20636f72652d7072656469636174655d207d0a616e792d707265646963617465203d207b206b696e643a2022616e79222c2076616c7565733a205b2b20636f72652d7072656469636174655d207d0a636f6d706172652d707265646963617465203d207b0a20206b696e643a2022636f6d70617265222c0a20206f703a20223d3d22202f2022213d22202f20223c22202f20223c3d22202f20223e22202f20223e3d222c0a20206c6566743a20636f72652d657870722c0a202072696768743a20636f72652d657870722c0a7d0a63616c6c2d707265646963617465203d207b0a20206b696e643a202263616c6c222c0a20207072656469636174653a20747374722c0a2020617267733a205b2a20636f72652d657870725d2c0a7d0a6f62737472756374696f6e2d707265646963617465203d207b0a20206b696e643a20226f62737472756374696f6e222c0a2020636f6f7264696e6174653a206661696c7572652d6964656e742c0a20207061796c6f61643a20636f72652d657870722c0a7d0a0a696e7075742d636f6e73747261696e74203d207b0a2020636f6f7264696e6174653a20747374722c0a2020736f757263653a2022776865726522202f2022636f6d70696c6572222c0a20207072656469636174653a20636f72652d7072656469636174652c0a7d0a0a3b202d2d2d20696e74656e74732c20626c6f636b732c20616e64206e6f646573202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a636f72652d696e74656e74203d207b0a2020696e7075743a20636f72652d747970652d7265662c0a20206f75747075743a20636f72652d747970652d7265662c0a202072657175697265644f7065726174696f6e50726f66696c653a20747374722c0a20203f2062617369733a20636f72652d657870722c0a2020696e707574436f6e73747261696e74733a205b2a20696e7075742d636f6e73747261696e745d2c0a2020636f72654576616c756174696f6e4275646765743a20636f72652d6275646765742c0a2020626f64793a20636f72652d626c6f636b2c0a20203f206f707469633a20636f72652d6f707469632c0a7d0a0a636f72652d627564676574203d207b0a20206d617853746570733a2075696e742c0a20206d6178416c6c6f636174656442797465733a2075696e742c0a20206d61784f757470757442797465733a2075696e742c0a7d0a0a636f72652d6f70746963203d207b0a20206f707469634b696e643a2022726576656c6174696f6e22202f20226166666563745265696e746567726174696f6e222c0a2020626f756e646172794b696e643a202270726f6a656374696f6e22202f2022616666656374222c0a20206170657274757265526571756972656d656e743a2061706572747572652d726571756972656d656e742c0a2020737570706f7274506f6c6963793a20747374722c0a20206c6f7373446973706f736974696f6e3a20747374722c0a7d0a0a636f72652d626c6f636b203d207b0a20206c6f63616c733a205b2a206c6f63616c2d7265665d2c0a20206e6f6465733a205b2a20636f72652d6e6f64655d2c0a2020726573756c743a20636f72652d657870722c0a7d0a0a636f72652d6e6f6465203d206c65742d6e6f6465202f20726571756972652d6e6f6465202f206566666563742d6e6f6465202f2067756172642d6e6f6465202f206272616e63682d6e6f6465202f0a202020202020202020202020666f722d6e6f6465202f206d617463682d6e6f6465202f2070726f6f662d6f626c69676174696f6e2d6e6f64650a0a6c65742d6e6f6465203d207b0a20206b696e643a20226c6574222c0a202062696e64696e673a206c6f63616c2d7265662c0a202076616c75653a20636f72652d657870722c0a7d0a726571756972652d6e6f6465203d207b0a20206b696e643a202272657175697265222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20206f6e4661696c7572653a20726571756972652d6661696c7572652d61726d2c0a7d0a726571756972652d6661696c7572652d61726d203d207465726d696e616c2d726571756972652d6661696c757265202f0a20202020202020202020202020202020202020202020636f6e74696e75652d6f6273747275637465642d726571756972652d6661696c7572650a7465726d696e616c2d726571756972652d6661696c757265203d207b0a20206b696e643a20227465726d696e616c222c0a2020726561736f6e3a206f62737472756374696f6e2d726561736f6e2c0a7d0a636f6e74696e75652d6f6273747275637465642d726571756972652d6661696c757265203d207b0a20206b696e643a2022636f6e74696e75654f627374727563746564222c0a2020726561736f6e3a206f62737472756374696f6e2d726561736f6e2c0a7d0a6f62737472756374696f6e2d726561736f6e203d207b0a2020726561736f6e4b696e643a20747374722c0a20207061796c6f61643a207b202a2074737472203d3e20636f72652d65787072207d2c0a7d0a6566666563742d6e6f6465203d207b0a20206b696e643a2022656666656374222c0a202062696e64696e673a206c6f63616c2d7265662c0a20206566666563743a20747374722c0a2020696e7075743a20636f72652d657870722c0a20206f62737472756374696f6e4d61703a207b202a206661696c7572652d6964656e74203d3e206f62737472756374696f6e2d61726d207d2c0a7d0a6f62737472756374696f6e2d61726d203d207b0a202062696e6465723a206c6f63616c2d7265662c0a202076616c75653a20636f72652d657870722c0a7d0a67756172642d6e6f6465203d207b0a20206b696e643a20226775617264222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20206f62737472756374696f6e3a20636f72652d657870722c0a7d0a6272616e63682d6e6f6465203d207b0a20206b696e643a20226272616e6368222c0a20207072656469636174653a20636f72652d7072656469636174652c0a20207468656e3a20636f72652d626c6f636b2c0a2020656c73653a20636f72652d626c6f636b2c0a7d0a666f722d6e6f6465203d207b0a20206b696e643a2022666f72222c0a202062696e6465723a206c6f63616c2d7265662c0a2020697465723a20636f72652d657870722c0a2020626f756e643a20636f72652d626f756e642c0a2020626f64793a20636f72652d626c6f636b2c0a7d0a6d617463682d6e6f6465203d207b0a20206b696e643a20226d61746368222c0a20207363727574696e65653a20636f72652d657870722c0a202061726d733a205b2b206d617463682d626c6f636b2d61726d5d2c0a7d0a6d617463682d626c6f636b2d61726d203d207b0a2020636173653a20747374722c0a20203f2062696e6465723a206c6f63616c2d7265662c0a2020626f64793a20636f72652d626c6f636b2c0a7d0a70726f6f662d6f626c69676174696f6e2d6e6f6465203d207b0a20206b696e643a202270726f6f66222c0a2020636f6f7264696e6174653a20747374722c0a20207072656469636174653a20636f72652d7072656469636174652c0a7d0a0a636f72652d626f756e64203d206c69746572616c2d626f756e64202f20636f6f7264696e6174652d626f756e640a6c69746572616c2d626f756e64203d207b206b696e643a20226c69746572616c222c2076616c75653a2075696e74207d0a636f6f7264696e6174652d626f756e64203d207b206b696e643a2022636f6f7264696e617465222c207265663a2074737472207d0a0a3b20536861726564207265736f757263652d7265662c207368613235362d6469676573742c206661696c7572652d6964656e742c2061706572747572652d726571756972656d656e742c20616e640a3b20636f72652d747970652d7265662061726520646566696e6564206f6e636520696e2065646963742d636f6d6d6f6e2e6364646c2e0a0a3b202d2d2d2065646963742d6c61777061636b2e6364646c202d2d2d0a3b2065646963742d6c61777061636b2e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f7220746865204564696374206c61777061636b206d616e696665737420616e64206578706f727420737572666163652e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e204a534f4e20696e207468652070726f73652073706563730a3b2069732061207265766965772072656e646572696e672067656e6572617465642066726f6d207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a6c61777061636b2d6d616e6966657374203d207b0a202061706956657273696f6e3a202265646963742e6c61777061636b2f7631222c0a202069643a20747374722c0a202076657273696f6e3a20747374722c0a20206163636570746564436f72654162693a205b2b20747374725d2c0a2020646570656e64656e636965733a205b2a206c61777061636b2d6465705d2c202020202020202020203b20616379636c69632c206469676573742d6c6f636b6564202845444943542d4c41575041434b2d4441472d303031290a20206578706f7274733a207265736f757263652d7265662c0a20203f2074617267657441646170746572733a205b2b207461726765742d616461707465725d2c2020203b207265717569726564206f6e6c7920696620616e792072756e74696d6520656666656374206578697374730a20203f2068656c706572436f6d706f6e656e743a2065786563757461626c652d636f6d706f6e656e742c203b2065786563757461626c652068656c70657273206361727279207468656972206f776e2073616e64626f782b6675656c0a202076657269666965723a2076657269666965722c202020202020202020202020202020202020202020203b20636c61737369666965643a206465636c61726174697665206f722065786563757461626c650a2020636f6d7061746962696c6974793a207265736f757263652d7265662c0a2020636f6e666f726d616e636546697874757265436f727075733a207265736f757263652d7265662c0a7d0a0a3b2041207665726966696572206973206569746865722061206465636c617261746976652072756c6573657420286e6f2072756e74696d6529206f7220616e2065786563757461626c650a3b20636f6d706f6e656e742e20416e2065786563757461626c65207665726966696572204d55535420636172727920697473206f776e2073616e64626f7820616e64206675656c206d6f64656c2c0a3b20736f2074686520736368656d6120656e666f726365732074686174206e6f2065786563757461626c6520636f6d706f6e656e74206973206c65667420756e626f756e6465640a3b202845444943542d4142492d56455249464945522d424f554e442d303031292e0a7665726966696572203d206465636c617261746976652d7665726966696572202f2065786563757461626c652d76657269666965720a6465636c617261746976652d7665726966696572203d207b20636c6173733a20226465636c61726174697665222c2072756c657365743a207265736f757263652d726566207d0a65786563757461626c652d7665726966696572203d207b0a2020636c6173733a202265786563757461626c65222c0a2020636f6d706f6e656e743a207265736f757263652d7265662c0a202073616e64626f783a207265736f757263652d7265662c0a20206675656c4d6f64656c3a207265736f757263652d7265662c0a7d0a0a3b20416e792065786563757461626c6520636f6d706f6e656e7420697320626f756e64656420627920697473206f776e2073616e64626f78202b206675656c206d6f64656c2e0a65786563757461626c652d636f6d706f6e656e74203d207b0a2020636f6d706f6e656e743a207265736f757263652d7265662c0a202073616e64626f783a207265736f757263652d7265662c0a20206675656c4d6f64656c3a207265736f757263652d7265662c0a7d0a0a6c61777061636b2d646570203d207b2069643a20747374722c2076657273696f6e3a20747374722c206469676573743a207368613235362d646967657374207d0a0a3b20416461707465722073656c656374696f6e206b65797320534f4c454c59206f666620746865206469676573742d6c6f636b65642060616363657074656454617267657450726f66696c65600a3b20286974732060696460206973207468652070726f66696c652069643b206974732060646967657374602070696e73207468652065786163742070726f66696c652f76657273696f6e292e2054686572650a3b20617265206e6f20696e646570656e64656e7420646973706c617920737472696e6773207468617420636f756c64206469736167726565207769746820746865206c6f636b2c20736f20610a3b207265736f6c7665722063616e6e6f742062696e6420616e206164617074657220746f206f6e6520746172676574207768696c6520746865206c6f636b2070726f76657320616e6f746865720a3b202845444943542d4c41575041434b2d414441505445522d54415247455449522d303031292e0a7461726765742d61646170746572203d207b0a2020616363657074656454617267657450726f66696c653a207265736f757263652d7265662c202020203b206469676573742d6c6f636b65642c20617574686f72697461746976652073656c6563746f720a2020616363657074656454617267657449723a207265736f757263652d7265662c2020202020202020203b206469676573742d6c6f636b65640a2020616461707465723a207265736f757263652d7265662c0a7d0a0a3b20536861726564207479706573207265736f757263652d72656620616e64207368613235362d6469676573742061726520646566696e6564206f6e636520696e0a3b2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a3b202d2d2d206578706f72742073757266616365202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a6c61777061636b2d6578706f727473203d207b0a202074797065733a205b2a206578706f727465642d747970655d2c0a2020636f6e7374616e74733a205b2a206578706f727465642d636f6e7374616e745d2c0a20207075726546756e6374696f6e733a205b2a20707572652d66756e6374696f6e5d2c0a2020656666656374733a205b2a2073656d616e7469632d6566666563745d2c0a20206f62737472756374696f6e733a205b2a206f62737472756374696f6e2d6465665d2c0a20203b206b65796564206279206f7065726174696f6e2d70726f66696c6520636f6f7264696e61746520e2869220756e697175656e65737320656e666f726365640a20203b202845444943542d4142492d4f5050524f46494c452d554e495155452d303031290a20203b206f7065726174696f6e2d70726f66696c65207265636f7264732074686973206c61777061636b206578706f72747320286f707469632074656d706c6174657320746861740a20203b2060696d706c656d656e7473602f6070726f66696c656020636c6175736573207265736f6c766520616761696e7374292e206f7065726174696f6e2d70726f66696c652069730a20203b20646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c202845444943542d4142492d4f5050524f46494c452d534c4f542d303031292e0a20206f7065726174696f6e50726f66696c65733a207b202a2074737472203d3e206f7065726174696f6e2d70726f66696c65207d2c20203b206b6579656420627920636f6f7264696e6174650a7d0a0a6578706f727465642d7479706520202020203d207b20636f6f7264696e6174653a20747374722c20646566696e6974696f6e3a20636f72652d747970652d726566207d0a6578706f727465642d636f6e7374616e74203d207b20636f6f7264696e6174653a20747374722c20747970653a20636f72652d747970652d7265662c2076616c75653a20616e79207d0a0a3b204120707572652068656c7065722069732061206469736372696d696e6174656420756e696f6e2062792060736f75726365602c20736f2074686520736368656d6120697473656c660a3b2067756172616e7465657320616e20696d706c656d656e746174696f6e20657869737473202845444943542d4c41575041434b2d505552452d494d504c2d303031293a0a3b2020202d20226564696374223a20617574686f72656420696e2045646963742f436f72653b2074686520436f726520626f6479206973206361727269656420696e6c696e6520286861736865640a3b20202020207769746820746865206578706f72742073757266616365292e2054686520736368656d61207265717569726573207468652060626f647960206669656c642e0a3b2020202d2022636f6d706f6e656e74223a20696d706c656d656e746564206f7574736964652045646963743b2063617272696573206e6f20696e6c696e6520626f647920616e6420696e73746561640a3b20202020206361727269657320697473206f776e206469676573742d6c6f636b65642060696d706c656d656e746174696f6e60202873616e64626f78202b206675656c292e20497420646f65730a3b20202020206e6f7420646570656e64206f6e20746865206f7074696f6e616c206d616e69666573742d6c6576656c2068656c706572436f6d706f6e656e742e0a707572652d66756e6374696f6e203d2065646963742d707572652d66756e6374696f6e202f20636f6d706f6e656e742d707572652d66756e6374696f6e0a0a707572652d66756e6374696f6e2d636f6d6d6f6e203d20280a2020636f6f7264696e6174653a20747374722c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020706172616d6574657254797065733a205b2a20636f72652d747970652d7265665d2c2020202020203b20616c6c20626f756e6465640a202072657475726e547970653a20636f72652d747970652d7265662c20202020202020202020202020203b20626f756e6465640a2020636f737454656d706c6174653a20747374722c0a202064657465726d696e69736d436c6173733a2022746f74616c22202f2022746f74616c2d776974682d74797065642d646961676e6f73746963222c0a290a0a65646963742d707572652d66756e6374696f6e203d207b0a2020707572652d66756e6374696f6e2d636f6d6d6f6e2c0a2020736f757263653a20226564696374222c0a2020626f64793a20636f72652d666e2d626f64792c2020202020202020202020202020202020202020203b20696e6c696e652c20686173682d7369676e69666963616e740a7d0a0a636f6d706f6e656e742d707572652d66756e6374696f6e203d207b0a2020707572652d66756e6374696f6e2d636f6d6d6f6e2c0a2020736f757263653a2022636f6d706f6e656e74222c0a20203b20746865206469676573742d6c6f636b656420636f6d706f6e656e7420696d706c656d656e74696e6720746869732068656c7065722e2052657175697265642061742074686520736368656d610a20203b206c6576656c20736f206120636f6d706f6e656e742068656c7065722063616e206e657665722076616c696461746520776974686f7574206120686173682d626f756e642c0a20203b2073616e64626f782b6675656c2d64657363726962656420696d706c656d656e746174696f6e202845444943542d4c41575041434b2d505552452d494d504c2d303031292e0a2020696d706c656d656e746174696f6e3a2065786563757461626c652d636f6d706f6e656e742c0a7d0a0a3b20636f72652d666e2d626f647920697320646566696e65642062792065646963742d636f72652e6364646c20616e6420617373656d626c656420776974682074686973206c61777061636b0a3b20736368656d612e2049742069732061207075726520436f72652066756e6374696f6e20626f64792c206e6f7420616e206566666563742d63617061626c6520636f72652d626c6f636b2e0a0a73656d616e7469632d656666656374203d207b0a2020636f6f7264696e6174653a20747374722c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020696e707574547970653a20636f72652d747970652d7265662c2020202020202020202020202020203b20626f756e6465640a20206f7574707574547970653a20636f72652d747970652d7265662c20202020202020202020202020203b20626f756e6465640a2020657865637574696f6e436c6173733a202270726f6f664f6e6c7922202f202272756e74696d65222c2020203b206f7274686f676f6e616c20746f207772697465436c6173730a20206566666563744b696e6448696e743a206566666563742d6b696e642c0a2020666f6f747072696e744f626c69676174696f6e3a20747374722c0a2020636f73744f626c69676174696f6e3a20747374722c0a20206566666563744661696c757265733a207b202a206661696c7572652d6964656e74203d3e206566666563742d6661696c7572652d626f6479207d2c20203b206b6579656420627920636f6f7264696e6174653b20756e697175650a20206775617264537570706f72743a20626f6f6c2c0a7d0a0a6f62737472756374696f6e2d646566203d207b0a2020636f6f7264696e6174653a20747374722c0a2020617574686f72697479436c6173733a20617574686f726974792d636c6173732c0a20207061796c6f6164536368656d613a20636f72652d747970652d7265662c20202020202020202020203b2074797065642c20626f756e64656420286d617920626520656d707479207265636f7264290a7d0a0a3b206566666563742d6661696c7572652d626f64792c206566666563742d6b696e642c20617574686f726974792d636c6173732c20616e6420636f72652d747970652d7265662061726520646566696e65640a3b206f6e636520696e2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a3b202d2d2d2065646963742d6c61777061636b2d616461707465722e6364646c202d2d2d0a3b2065646963742d6c61777061636b2d616461707465722e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f72206f6e6520646972656374206465636c61726174697665206c61777061636b2074617267657420616461707465722e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a3b0a3b2054686520656e636c6f73696e67206c61777061636b206d616e69666573742073656c6563747320746865206578616374207461726765742070726f66696c652c207461726765742049522c0a3b20616e642061646170746572207265736f75726365206469676573742e2054686f7365206964656e74697469657320617265206e6f7420726570656174656420686572652e0a0a6c61777061636b2d61646170746572203d207b0a202061706956657273696f6e3a202265646963742e6c61777061636b2d616461707465722f7631222c0a2020636c6173733a20226465636c61726174697665222c0a20206f7065726174696f6e50726f66696c65733a207b0a202020202a2074737472203d3e206c61777061636b2d616461707465722d6f7065726174696f6e2d70726f66696c650a20207d2c0a2020656666656374496d706c656d656e746174696f6e733a207b0a202020202a2074737472203d3e206c61777061636b2d616461707465722d6566666563740a20207d2c0a2020627564676574733a207b0a202020202a2074737472203d3e206c61777061636b2d616461707465722d6275646765740a20207d2c0a7d0a0a3b204b657973206172652063616e6f6e6963616c206c61777061636b206f7065726174696f6e2d70726f66696c6520636f6f7264696e617465732e0a6c61777061636b2d616461707465722d6f7065726174696f6e2d70726f66696c65203d207b0a2020636f72653a20747374722c0a202073656d616e746963456666656374733a205b2b20747374725d2c0a7d0a0a3b204b657973206172652063616e6f6e6963616c206c61777061636b2073656d616e7469632d65666665637420636f6f7264696e617465732e20466f6f747072696e742c20636f73742c20616e640a3b206661696c757265206669656c6473206d7573742065786163746c792064697363686172676520746865206d61746368696e67206578706f72746564206566666563742e0a6c61777061636b2d616461707465722d656666656374203d207b0a2020746172676574496e7472696e7369633a20747374722c0a2020746172676574436f6e66696775726174696f6e3a207265736f757263652d7265662c0a20207772697465436c6173733a206c61777061636b2d616461707465722d77726974652d636c6173732c0a2020666f6f747072696e744f626c69676174696f6e3a20747374722c0a2020636f73744f626c69676174696f6e3a20747374722c0a20206661696c7572654d617070696e67733a207b202a206661696c7572652d6964656e74203d3e2074737472207d2c0a7d0a0a3b204b657973206172652063616e6f6e6963616c206578706f7274656420636f73742d6f626c69676174696f6e20636f6f7264696e617465732e0a6c61777061636b2d616461707465722d627564676574203d207b0a20206d617853746570733a2075696e742c0a20206d6178416c6c6f636174656442797465733a2075696e742c0a20206d61784f757470757442797465733a2075696e742c0a7d0a0a6c61777061636b2d616461707465722d77726974652d636c617373203d20226e6f6e6522202f20227265616422202f202263726561746522202f2022656e7375726522202f0a20202020202020202020202020202020202020202020202020202020202022617070656e6422202f20227265706c61636522202f202264656c65746522202f2022637573746f6d220a0a3b206661696c7572652d6964656e7420697320646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c2e0a0a3b202d2d2d2065646963742d7461726765742d70726f66696c652e6364646c202d2d2d0a3b2065646963742d7461726765742d70726f66696c652e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f7220746865204564696374207461726765742070726f66696c65206d616e69666573742e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76310a3b202873656520535045435f636f6e74696e75756d2d636f6e74726163742d62756e646c652d76312e6d64292e204a534f4e20696e207468652070726f736520737065637320697320610a3b207265766965772072656e646572696e672067656e6572617465642066726f6d207468697320736368656d613b2074686973204344444c206973207468652073696e676c6520736f757263650a3b206f66207472757468202845444943542d4142492d4e4f4455502d303031292e0a0a7461726765742d70726f66696c652d6d616e6966657374203d207b0a202061706956657273696f6e3a202265646963742e7461726765742d70726f66696c652f7631222c0a202069643a20747374722c202020202020202020202020202020202020202020202020203b20652e672e20226563686f2e64706f220a202076657273696f6e3a20747374722c20202020202020202020202020202020202020203b20652e672e202231220a20206163636570746564436f72654162693a205b2b20747374725d2c20202020202020203b20652e672e205b2265646963742e636f72652f7631225d0a0a2020696e7472696e736963733a207265736f757263652d7265662c0a2020696e7472696e7369634e616d6573706163653a20747374722c0a20203b207075626c697368657320746869732070726f66696c652773206f7065726174696f6e2d70726f66696c65207265636f72647320286f707469632074656d706c6174657320746861740a20203b206070726f66696c65602f60696d706c656d656e74736020636c6175736573207265736f6c766520616761696e7374292e205265666572656e63657320616e0a20203b206f7065726174696f6e2d70726f66696c65732d646f63756d656e74202845444943542d4142492d4f5050524f46494c452d534c4f542d303031292e0a20206f7065726174696f6e50726f66696c65733a207265736f757263652d7265662c0a2020666f6f747072696e74416c67656272613a207265736f757263652d7265662c0a2020636f7374416c67656272613a207265736f757263652d7265662c0a202074617267657449723a207265736f757263652d7265662c0a20206f62737472756374696f6e5461786f6e6f6d793a207265736f757263652d7265662c0a202076657269666965723a207265736f757263652d7265662c0a20206c6f77657265723a207265736f757263652d7265662c0a202073616e64626f783a207265736f757263652d7265662c0a20206675656c4d6f64656c3a207265736f757263652d7265662c0a0a20203b206669656c647320746865206c616e67756167652073706563207265717569726573206f662065766572792070726f66696c650a202062756e646c6550726f66696c653a207265736f757263652d7265662c0a202067656e657261746564417274696661637450726f66696c65733a205b2a207265736f757263652d7265665d2c0a202063616e6f6e6963616c456e636f64696e6752756c65733a207265736f757263652d7265662c0a20203b20412070726f66696c65207468617420616363657074732074686520646972656374206465636c61726174697665206c61777061636b2d6164617074657220414249206e616d65732069740a20203b2065786163746c79206f6e63652e2050726f66696c6573207468617420646f206e6f7420636f6e73756d65206c61777061636b206164617074657273206c6561766520746869730a20203b206f7074696f6e616c20736c6f7420616273656e74206f7220656d7074792e0a20203f2061636365707465644c61777061636b416461707465724162693a205b5d202f205b2265646963742e6c61777061636b2d616461707465722f7631225d2c0a2020646961676e6f737469634162693a207265736f757263652d7265662c0a0a20203b206170706c69636174696f6e20646f637472696e650a20206170706c69636174696f6e4d6f64656c3a202261746f6d6963222c0a202072656164436f6e73697374656e63793a20226170706c69636174696f6e2d736e617073686f7422202f20747374722c0a202067756172644576616c756174696f6e3a2022707265636f6d6d69742d61746f6d696322202f20747374722c0a20206f62737472756374696f6e526f6c6c6261636b3a20226e6f2d76697369626c652d6566666563747322202f20747374722c0a20206d756c74695461726765743a20626f6f6c2c0a20203b207768657468657220746865207461726765742063616e206576616c7561746520707265636f6d6d697420706f7374636f6e646974696f6e20286067756172616e746565602920636865636b730a20203b20696e73696465207468652061746f6d6963206170706c69636174696f6e20756e6974202845444943542d5441524745542d504f5354434f4e442d303031290a2020706f7374636f6e646974696f6e537570706f72743a20626f6f6c2c0a0a202064657465726d696e6973746963457865637574696f6e3a207265736f757263652d7265662c0a2020636f6e666f726d616e636546697874757265436f727075733a207265736f757263652d7265662c0a7d0a0a3b20536861726564207479706573207265736f757263652d72656620616e64207368613235362d6469676573742061726520646566696e6564206f6e636520696e0a3b2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d6120627920746865206275696c640a3b202845444943542d4142492d4e4f4455502d303031292e205468657920617265206e6f74207265646566696e656420686572652e0a0a3b202d2d2d20696e7472696e736963207369676e6174757265202d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a3b20546865206172746966616374207265666572656e63656420627920746865206d616e696665737427732060696e7472696e7369637360207265736f757263652d726566206973207468650a3b20696e7472696e7369632d7369676e617475726520636f7270757320646f63756d656e742062656c6f772e20497473206c61796f757420697320666978656420736f2074776f0a3b20696e646570656e64656e742070726f66696c65732076616c69646174652f686173682074686520636f72707573206964656e746963616c6c790a3b202845444943542d4142492d494e5452494e534943532d444f432d303031292e0a0a3b20696e7472696e736963732069732061204d4150206b6579656420627920636f6f7264696e6174652c20736f2074686520736368656d6120697473656c6620656e666f726365730a3b20636f6f7264696e61746520756e697175656e6573732e20412070726f766964657220726563656976657320746865207265736f6c76656420636f7270757320617320610a3b206469676573742d626f756e642073656d616e74696320696e70757420616e64207265736f6c76657320636f6f7264696e617465732077697468696e20746861742061727469666163742e0a3b2045616368206d6170206b6579204d55535420657175616c20697473207265636f726427732060636f6f7264696e61746560206669656c640a3b202845444943542d4142492d494e5452494e5349432d554e495155452d303031292e0a696e7472696e736963732d646f63756d656e74203d207b0a202061706956657273696f6e3a202265646963742e7461726765742d70726f66696c652e696e7472696e736963732f7631222c0a2020696e7472696e736963733a207b202a2074737472203d3e20696e7472696e736963207d2c0a7d0a0a3b20546865206172746966616374207265666572656e63656420627920746865206d616e6966657374277320606f7065726174696f6e50726f66696c657360207265736f757263652d7265662e0a3b206f7065726174696f6e2d70726f66696c65202f206f707469632d74656d706c6174652061726520646566696e656420696e2065646963742d636f6d6d6f6e2e6364646c2e204b657965642062790a3b20636f6f7264696e61746520736f207265736f6c7574696f6e2063616e2774207069636b206265747765656e2074776f2073616d652d636f6f7264696e6174652070726f66696c65730a3b202845444943542d4142492d4f5050524f46494c452d534c4f542d3030312c2045444943542d4142492d4f5050524f46494c452d554e495155452d303031292e0a6f7065726174696f6e2d70726f66696c65732d646f63756d656e74203d207b0a202061706956657273696f6e3a202265646963742e7461726765742d70726f66696c652e6f7065726174696f6e2d70726f66696c65732f7631222c0a202070726f66696c65733a207b202a2074737472203d3e206f7065726174696f6e2d70726f66696c65207d2c0a7d0a0a3b2041207479706564207072652d6c6f776572696e67207175657374696f6e20746861742063616e2062652070726f706f73656420627920576174736f6e206f7220616e206167656e7420616e640a3b20636865636b65642062792074686520636f6d70696c65722e2049742069732063616e6f6e6963616c2d43424f5220656e636f64656420756e6465720a3b206065646963742e6c6f776572696e672d726571756972656d656e74732f7631603b2074686520636f6d70696c657220636865636b7320746869732061727469666163742c206e6f74207468650a3b2070726f736520746861742070726f64756365642069742e0a6c6f776572696e672d726571756972656d656e7473203d207b0a202061706956657273696f6e3a202265646963742e6c6f776572696e672d726571756972656d656e74732f7631222c0a20206f7065726174696f6e50726f66696c653a20747374722c0a202073656d616e746963456666656374733a205b2a2073656d616e7469632d6566666563742d726571756972656d656e745d2c0a202072657175697265645772697465436c61737365733a205b2a2077726974652d636c6173735d2c0a202067756172644b696e64733a205b2a2067756172642d6b696e645d2c0a202061746f6d69636974793a2061746f6d69636974792d726571756972656d656e742c0a2020706f7374636f6e646974696f6e537570706f72743a20626f6f6c2c0a20206f62737472756374696f6e436f6f7264696e617465733a205b2a20747374725d2c0a2020666f6f747072696e744f626c69676174696f6e733a205b2a20747374725d2c0a2020636f73744f626c69676174696f6e733a205b2a20747374725d2c0a20206f70746963436f6e74726163743a20747374722c0a7d0a0a73656d616e7469632d6566666563742d726571756972656d656e74203d207b0a2020636f6f7264696e6174653a20747374722c0a20207772697465436c6173733a2077726974652d636c6173732c0a202067756172644b696e64733a205b2a2067756172642d6b696e645d2c0a20206f62737472756374696f6e436f6f7264696e617465733a205b2a20747374725d2c0a2020666f6f747072696e744f626c69676174696f6e733a205b2a20747374725d2c0a2020636f73744f626c69676174696f6e733a205b2a20747374725d2c0a7d0a0a77726974652d636c617373203d20226e6f6e6522202f20227265616422202f202263726561746522202f2022656e7375726522202f2022617070656e6422202f0a2020202020202020202020202020227265706c61636522202f202264656c65746522202f20747374720a67756172642d6b696e64203d2022707265636f6d6d69742d61746f6d696322202f20747374720a61746f6d69636974792d726571756972656d656e74203d202261746f6d696322202f20747374720a0a3b20412067656e75696e6520756e696f6e3a207075726520636f6e7374727563746f7273206361727279206e6f20656666656374206b696e64206f72206661696c757265733b206566666563740a3b20696e7472696e73696373206d757374202845444943542d5441524745542d494e5452494e5349432d434c4153532d303031292e2054686520736368656d6120656e666f7263657320746869732c0a3b206e6f74206120636f6d6d656e742e0a0a3b2054686520696e7472696e736963277320636f6f7264696e6174652069732074686520696e7472696e73696373206d6170204b45592c206e6f7420612076616c7565206669656c642c20736f207468650a3b206b657920616e6420636f6f7264696e6174652063616e206e65766572206469736167726565202845444943542d4142492d494e5452494e5349432d554e495155452d303031292e0a696e7472696e736963203d20707572652d696e7472696e736963202f206566666563742d696e7472696e7369630a0a707572652d696e7472696e736963203d207b0a2020696e7472696e736963436c6173733a202270757265222c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020617267756d656e7454797065733a205b2a20636f72652d747970652d7265665d2c0a202072657475726e547970653a20636f72652d747970652d7265662c0a20206775617264537570706f72743a2066616c73652c0a2020666f6f747072696e7454656d706c6174653a20747374722c0a2020636f737454656d706c6174653a20747374722c0a20207772697465436c6173733a20226e6f6e65222c0a7d0a0a6566666563742d696e7472696e736963203d207b0a2020696e7472696e736963436c6173733a2022656666656374222c0a202074797065506172616d65746572733a205b2a20747374725d2c0a2020617267756d656e7454797065733a205b2a20636f72652d747970652d7265665d2c0a202072657475726e547970653a20636f72652d747970652d7265662c0a20206566666563744b696e643a206566666563742d6b696e642c0a20203b206d6170206b65796564206279206661696c75726520636f6f7264696e61746520286661696c7572652d6964656e74293b20746865206661696c75726520636f6f7264696e6174652069730a20203b20746865206b65792c206e6f7420612076616c7565206669656c642c20736f20756e697175656e657373206973207374727563747572616c0a20203b202845444943542d4142492d4641494c5552452d554e495155452d303031292e0a20206566666563744661696c757265733a207b202a206661696c7572652d6964656e74203d3e206566666563742d6661696c7572652d626f6479207d2c0a20206775617264537570706f72743a20626f6f6c2c0a2020666f6f747072696e7454656d706c6174653a20747374722c0a2020636f737454656d706c6174653a20747374722c0a20207772697465436c6173733a20227265616422202f202263726561746522202f2022656e7375726522202f2022617070656e6422202f20227265706c61636522202f0a20202020202020202020202020202264656c65746522202f2022637573746f6d222c0a202063616e5061727469636970617465496e41746f6d696347756172643a20626f6f6c2c0a7d0a0a3b206566666563742d6661696c7572652d626f64792c206566666563742d6b696e642c20617574686f726974792d636c6173732c20616e6420636f72652d747970652d7265662061726520646566696e65640a3b206f6e636520696e2065646963742d636f6d6d6f6e2e6364646c20616e6420617373656d626c65642077697468207468697320736368656d61202845444943542d4142492d4e4f4455502d303031292e0a0a3b202d2d2d2065646963742d617574686f726974792d66616374732e6364646c202d2d2d0a3b2065646963742d617574686f726974792d66616374732e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f722074686520666972737420636f6d70696c65722d636f6e7465787420617574686f726974792d666163747320646f63756d656e742e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a3b0a3b205468697320736368656d6120697320617373656d626c656420776974682065646963742d636f6d6d6f6e2e6364646c20736f20736f757263652e6469676573742075736573207468650a3b20736861726564207368613235362d6469676573742074797065642076616c75652e204a534f4e2069732061207265766965772f696e7075742072656e646572696e673a206974730a3b20607368613235363a3c3634206865783e6020736f75726365206469676573742069732070726f6a656374656420746f205b60736861323536602c203332207261772062797465735d206f6e0a3b2074686520776972652c20616e64206974732066616374206172726179732070726f6a65637420746f2074686520636f6f7264696e6174652d6b65796564206d6170732062656c6f772e0a0a617574686f726974792d6661637473203d207b0a202061706956657273696f6e3a202265646963742e617574686f726974792d66616374732f7631222c0a2020736f757263653a20617574686f726974792d666163742d736f757263652c0a20206f7065726174696f6e50726f66696c65733a207b202a2074737472203d3e20617574686f726974792d6f7065726174696f6e2d70726f66696c652d66616374207d2c0a20206566666563745772697465436c61737365733a207b202a2074737472203d3e20617574686f726974792d77726974652d636c617373207d2c0a2020627564676574733a207b202a2074737472203d3e20617574686f726974792d6275646765742d66616374207d2c0a7d0a0a617574686f726974792d666163742d736f75726365203d207b0a20206b696e643a20226c61777061636b22202f202274617267657450726f66696c65222c0a2020636f6f7264696e6174653a20747374722c0a20206469676573743a207368613235362d6469676573742c0a7d0a0a3b20546865206d6170206b65792069732074686520736f75726365206f7065726174696f6e2d70726f66696c6520636f6f7264696e6174652e204974206973206e6f7420726570656174656420696e0a3b207468652076616c75652c20736f2061206b657920616e6420656d62656464656420636f6f7264696e6174652063616e6e6f742064697361677265652e20416c6c6f7765642077726974650a3b20636c61737365732061726520612063616e6f6e6963616c206d61702d7365743a2074686520636c6173732069732074686520756e69717565206b657920616e64206e756c6c206973207468650a3b20756e6974206d61726b65722e2043616e6f6e6963616c2043424f52206669786573206b6579206f7264657220776974686f75742061207365636f6e64206f72646572696e672072756c652e0a617574686f726974792d6f7065726174696f6e2d70726f66696c652d66616374203d207b0a2020636f72653a20747374722c0a2020616c6c6f7765645772697465436c61737365733a207b202a20617574686f726974792d77726974652d636c617373203d3e206e756c6c207d2c0a7d0a0a3b20546865206566666563745772697465436c6173736573206d6170206b6579206973207468652073656d616e7469632065666665637420636f6f7264696e6174652e2054686520627564676574730a3b206d6170206b65792069732074686520736f757263652062756467657420636f6f7264696e6174652e2043616e6f6e6963616c2043424f52206d61702d6b657920756e697175656e6573730a3b206d616b6573206475706c6963617465206661637420636f6f7264696e61746573207374727563747572616c6c7920756e726570726573656e7461626c652e0a617574686f726974792d6275646765742d66616374203d207b0a20206d617853746570733a2075696e742c0a20206d6178416c6c6f636174656442797465733a2075696e742c0a20206d61784f757470757442797465733a2075696e742c0a7d0a0a3b20417574686f726974794661637473446f63756d656e7420763120696e74656e74696f6e616c6c792061636365707473206f6e6c792074686520777269746520636c6173736573207468650a3b2063757272656e7420636f6d70696c6572206d6f64656c2063616e20636f6e73756d652e2060637573746f6d602069732074686520736f6c6520763120637573746f6d207370656c6c696e673b0a3b20617262697472617279207461726765742d70726f66696c6520657874656e73696f6e20737472696e677320646f206e6f7420656e746572207468697320636f6d70696c657220706174682e0a617574686f726974792d77726974652d636c617373203d20226e6f6e6522202f20227265616422202f202263726561746522202f2022656e7375726522202f2022617070656e6422202f0a202020202020202020202020202020202020202020202020227265706c61636522202f202264656c65746522202f2022637573746f6d220a0a3b202d2d2d2065646963742d726573756c742d70726f6a656374696f6e2e6364646c202d2d2d0a3b20535044582d4c6963656e73652d4964656e7469666965723a204170616368652d322e300a3b2065646963742d726573756c742d70726f6a656374696f6e2e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f7220636f6d70696c65722d6f776e6564206170706c69636174696f6e2d726573756c742070726f6a656374696f6e732e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a0a726573756c742d70726f6a656374696f6e203d207b0a2020736368656d613a202265646963742e726573756c742d70726f6a656374696f6e2f7631222c0a20206f7065726174696f6e436f6f7264696e6174653a20626f756e6465642d70726f6a656374696f6e2d746578742c0a20206f7574707574547970653a20626f756e6465642d70726f6a656374696f6e2d746578742c0a20206d61784f757470757442797465733a2075696e74202e677420302c0a202065787072657373696f6e3a20726573756c742d70726f6a656374696f6e2d657870722c0a7d0a0a726573756c742d70726f6a656374696f6e2d65787072203d20726573756c742d70726f6a656374696f6e2d7265636f7264202f20726573756c742d70726f6a656374696f6e2d736f757263650a0a726573756c742d70726f6a656374696f6e2d7265636f7264203d207b0a20206b696e643a20227265636f7264222c0a20203b2054686520726f6f74207265636f726420636f756e7473206173206f6e65206f66207468652052757374206465636f6465722773203235362065787072657373696f6e206e6f6465732e0a20203b204e657374656420616767726567617465206e6f646520636f756e742072656d61696e7320616e20617574686f7269746174697665206465636f64657220636865636b2e0a20206669656c64733a207b20302a32353520626f756e6465642d70726f6a656374696f6e2d74657874203d3e20726573756c742d70726f6a656374696f6e2d65787072207d2c0a7d0a0a726573756c742d70726f6a656374696f6e2d736f75726365203d207b0a20206b696e643a2022736f75726365222c0a2020736f757263653a20726573756c742d70726f6a656374696f6e2d736f757263652d6b696e642c0a20203b204d617463686573204d41585f524553554c545f50524f4a454354494f4e5f504154485f5345474d454e545320696e2065646963742d73796e7461782e0a2020706174683a205b302a333220626f756e6465642d70726f6a656374696f6e2d746578745d2c0a7d0a0a726573756c742d70726f6a656374696f6e2d736f757263652d6b696e64203d0a20207b206b696e643a20226170706c69636174696f6e496e70757422207d202f0a20207b0a202020206b696e643a20226361706162696c697479526573756c74222c0a202020207374657049643a20626f756e6465642d70726f6a656374696f6e2d746578742c0a20207d0a0a626f756e6465642d70726f6a656374696f6e2d74657874203d2074737472202e73697a652028312e2e31303234290a0a3b202d2d2d2065646963742d7461726765742d69722e6364646c202d2d2d0a3b20535044582d4c6963656e73652d4964656e7469666965723a204170616368652d322e300a3b2065646963742d7461726765742d69722e6364646c0a3b2043616e6f6e6963616c20736368656d6120666f72207468652045646963742d6f776e65642054617267657420495220617274696661637420656e76656c6f70652e0a3b20417574686f7269746174697665206279746520656e636f64696e673a2065646963742e63616e6f6e6963616c2d63626f722f76312e0a3b0a3b205468697320736368656d6120697320617373656d626c656420776974682065646963742d636f6d6d6f6e2e6364646c20616e642065646963742d636f72652e6364646c2e2049740a3b2064656c696265726174656c792072657573657320436f72652065787072657373696f6e732c20707265646963617465732c20627564676574732c206c6f63616c207265666572656e6365732c0a3b206f62737472756374696f6e20726561736f6e732c20616e64206f62737472756374696f6e2061726d7320736f2074686520736368656d61206d617463686573207468652076616c75650a3b20656d6974746564206279207468652063616e6f6e6963616c2054617267657420495220656e636f64657220726174686572207468616e20726573746174696e672074686f73652074797065732e0a3b2049742064657363726962657320746865207374727563747572616c207368617065206f662076616c6964206c6f776572696e672d70726f6475636564206172746966616374732e205468650a3b206c6f776572696e6720616e6420656e636f64657220636f6e7472616374732073657061726174656c7920656e666f7263652073656d616e746963206964656e7469666965722072756c65730a3b20616e642063616e6f6e6963616c206f72646572696e672f64656475706c69636174696f6e20666f72207365742d6c696b652076616c7565732e0a0a3b2054617267657420495220656e636f64696e672072656a6563747320616e20656d707479207461726765742d70726f66696c6520636f6f7264696e617465206265666f72652062797465730a3b2065786973742c20736f207468697320726f6f74207469676874656e732074686520736861726564207374727563747572616c207265736f757263652d726566206163636f7264696e676c792e0a7461726765742d69722d7265736f757263652d726566203d207b0a202069643a2074737472202e7265676578702022283f73292e2b222c0a20206469676573743a207368613235362d6469676573742c0a7d0a0a7461726765742d69722d6172746966616374203d207461726765742d69722d636c6f7365642d6172746966616374202f207461726765742d69722d6c65676163792d61727469666163740a0a7461726765742d69722d61727469666163742d636f6d6d6f6e203d20280a20206b696e643a202274617267657449724172746966616374222c0a2020646f6d61696e3a20747374722c0a202074617267657450726f66696c653a207461726765742d69722d7265736f757263652d7265662c0a2020736f75726365436f7265436f6f7264696e6174653a2074737472202e7265676578702022283f73292e2b222c0a290a0a7461726765742d69722d636c6f7365642d6172746966616374203d207b0a20207461726765742d69722d61727469666163742d636f6d6d6f6e2c0a202073656d616e746963436c6f737572653a207461726765742d69722d73656d616e7469632d636c6f737572652c0a2020696e74656e74733a207b202a2074737472203d3e207461726765742d69722d696e74656e74207d2c0a7d0a0a7461726765742d69722d6c65676163792d6172746966616374203d207b0a20207461726765742d69722d61727469666163742d636f6d6d6f6e2c0a2020696e74656e74733a207b202a2074737472203d3e207461726765742d69722d6c65676163792d696e74656e74207d2c0a7d0a0a7461726765742d69722d73656d616e7469632d636c6f73757265203d207b0a2020736f75726365436f72653a207461726765742d69722d7265736f757263652d7265662c0a20206c61777061636b733a205b2a207461726765742d69722d7265736f757263652d7265665d2c0a7d0a0a7461726765742d69722d696e74656e74203d207b0a20207461726765742d69722d696e74656e742d636f6d6d6f6e2c0a20203f2062617369733a20636f72652d657870722c0a7d0a0a7461726765742d69722d6c65676163792d696e74656e74203d207b0a20207461726765742d69722d696e74656e742d636f6d6d6f6e2c0a7d0a0a7461726765742d69722d696e74656e742d636f6d6d6f6e203d20280a20206f7065726174696f6e50726f66696c653a20747374722c0a2020696e707574436f6e73747261696e74733a205b2a20696e7075742d636f6e73747261696e745d2c0a2020636f72654576616c756174696f6e4275646765743a20636f72652d6275646765742c0a2020726571756972656d656e74733a205b2a207461726765742d69722d726571756972656d656e745d2c0a202073746570733a205b2a207461726765742d69722d737465705d2c0a2020726573756c743a20636f72652d657870722c0a290a0a7461726765742d69722d726571756972656d656e74203d207b0a202069643a20747374722c0a20207072656469636174653a20636f72652d7072656469636174652c0a20206f6e4661696c7572653a20726571756972652d6661696c7572652d61726d2c0a7d0a0a7461726765742d69722d73746570203d207b0a202069643a20747374722c0a202062696e64696e673a206c6f63616c2d7265662c0a20206566666563743a20747374722c0a2020746172676574496e7472696e7369633a20747374722c0a2020696e7075743a20636f72652d657870722c0a20206f62737472756374696f6e4661696c757265733a205b2a206661696c7572652d6964656e745d2c0a20206f62737472756374696f6e41726d733a207b202a206661696c7572652d6964656e74203d3e206f62737472756374696f6e2d61726d207d2c0a7d0a", + "rawSha256": "ff5405708185e0bcf33dac263000fcb772c79e21145ad69da7cad0692e1a9552" }, "contracts": [ {"contract": "authority-facts", "rootRule": "authority-facts"}, @@ -13,6 +13,7 @@ {"contract": "lawpack-exports", "rootRule": "lawpack-exports"}, {"contract": "lawpack-manifest", "rootRule": "lawpack-manifest"}, {"contract": "lowering-requirements", "rootRule": "lowering-requirements"}, + {"contract": "result-projection", "rootRule": "result-projection"}, {"contract": "target-ir-artifact", "rootRule": "target-ir-artifact"}, {"contract": "target-profile-intrinsics", "rootRule": "intrinsics-document"}, {"contract": "target-profile-manifest", "rootRule": "target-profile-manifest"}, @@ -23,6 +24,7 @@ {"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.result-projection.artifact/v1", "rootRule": "result-projection"}, {"domain": "edict.target-ir.artifact/v1", "rootRule": "target-ir-artifact"}, {"domain": "edict.target-profile/v1", "rootRule": "target-profile-manifest"} ], diff --git a/schemas/edict-provider/echo-provider-semantics-v1.json b/schemas/edict-provider/echo-provider-semantics-v1.json index 3a497b03..659b424a 100644 --- a/schemas/edict-provider/echo-provider-semantics-v1.json +++ b/schemas/edict-provider/echo-provider-semantics-v1.json @@ -539,6 +539,12 @@ "domain": "edict.lowering-requirements/v1", "schemaRole": "schema.echo-provider-artifacts" }, + { + "role": "result-projection.echo-operation", + "kind": "auxiliary", + "domain": "edict.result-projection.artifact/v1", + "schemaRole": "schema.echo-provider-artifacts" + }, { "role": "source.echo-operation", "kind": "auxiliary", @@ -771,6 +777,12 @@ "format": "selfContainedCddlV1", "rootRule": "lowering-requirements" }, + { + "domain": "edict.result-projection.artifact/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "result-projection" + }, { "domain": "edict.source/v1", "schemaRole": "schema.echo-provider-artifacts", @@ -790,4 +802,4 @@ "rootRule": "target-profile-manifest" } ] -} \ No newline at end of file +} 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 da7bace8..632d8807 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:e2a6a539a7156296c18ff1bc02f80dcabf62b42bb4314d0737527869e43986d6"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:ce1af559551f8b8242c4b290b620c5a28323b9e43f8bc6bb161a191001b6f4b9"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:8c570362671a0b1cd1a992d8210e4a90ffd153ad06dcdf1e0cb36033cc971e2c"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:1b105d1b1f6cdf5fecdef98b7adeb238525047d43581fe9fd8c44fd213e1788e"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:6b9076ae02730797fddf60a93606df3de245a1c6bfbd845486799b7310d002a2"}],"generationInputDigest":"sha256:49646ba46efe7b070ff1605bf7b148e6d35611a570015e9b08fa7d30206ec7c7","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:a5d5ea82a9e64aa78c4a44204d3e8919c1c590febb967f1d31639fdc2a20a96c"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:f78dc8bb32f04f3e246f57e4228077c2a243827dd243525b9bd2e1d81dfa07ff"}]} \ 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:e2a6a539a7156296c18ff1bc02f80dcabf62b42bb4314d0737527869e43986d6"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:ce1af559551f8b8242c4b290b620c5a28323b9e43f8bc6bb161a191001b6f4b9"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:8c570362671a0b1cd1a992d8210e4a90ffd153ad06dcdf1e0cb36033cc971e2c"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:1b105d1b1f6cdf5fecdef98b7adeb238525047d43581fe9fd8c44fd213e1788e"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:730ce72f6658fe8cc9302221c32ad5992492e190674ddd69c1b164749d2bb669"}],"generationInputDigest":"sha256:57f5f67172544014af9c92e658301b9fcec69fd77fba9d251b258b59e3591380","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:ff5405708185e0bcf33dac263000fcb772c79e21145ad69da7cad0692e1a9552"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:e31d0452bf9d8ba84eaa1ce8c09fa1c25f740decd0ab08cd9c2fde533bdef1fa"}]} \ 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 e333e6dc..0ba69ca3 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:e2a6a539a7156296c18ff1bc02f80dcabf62b42bb4314d0737527869e43986d6"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:ce1af559551f8b8242c4b290b620c5a28323b9e43f8bc6bb161a191001b6f4b9"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:8c570362671a0b1cd1a992d8210e4a90ffd153ad06dcdf1e0cb36033cc971e2c"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:1b105d1b1f6cdf5fecdef98b7adeb238525047d43581fe9fd8c44fd213e1788e"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:6b9076ae02730797fddf60a93606df3de245a1c6bfbd845486799b7310d002a2"}],"generationInputDigest":"sha256:49646ba46efe7b070ff1605bf7b148e6d35611a570015e9b08fa7d30206ec7c7","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52","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:d448084da79f0cca20fa538f188e414d37192be88b127facc0056a4571da7741","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:a5d5ea82a9e64aa78c4a44204d3e8919c1c590febb967f1d31639fdc2a20a96c"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:f78dc8bb32f04f3e246f57e4228077c2a243827dd243525b9bd2e1d81dfa07ff"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:e2a6a539a7156296c18ff1bc02f80dcabf62b42bb4314d0737527869e43986d6"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:ce1af559551f8b8242c4b290b620c5a28323b9e43f8bc6bb161a191001b6f4b9"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:8c570362671a0b1cd1a992d8210e4a90ffd153ad06dcdf1e0cb36033cc971e2c"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:1b105d1b1f6cdf5fecdef98b7adeb238525047d43581fe9fd8c44fd213e1788e"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:730ce72f6658fe8cc9302221c32ad5992492e190674ddd69c1b164749d2bb669"}],"generationInputDigest":"sha256:57f5f67172544014af9c92e658301b9fcec69fd77fba9d251b258b59e3591380","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346","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:998426658fbcbd44bff4f28d0d4c82df7aaf05bdbcdb736db9cf481a1948ec82","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:ff5405708185e0bcf33dac263000fcb772c79e21145ad69da7cad0692e1a9552"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:e31d0452bf9d8ba84eaa1ce8c09fa1c25f740decd0ab08cd9c2fde533bdef1fa"}]} \ No newline at end of file diff --git a/schemas/edict-provider/generated/v1/primary/schema.echo-provider-artifacts.cddl b/schemas/edict-provider/generated/v1/primary/schema.echo-provider-artifacts.cddl index 32ecdc59..ea161b3d 100644 --- a/schemas/edict-provider/generated/v1/primary/schema.echo-provider-artifacts.cddl +++ b/schemas/edict-provider/generated/v1/primary/schema.echo-provider-artifacts.cddl @@ -583,7 +583,7 @@ lawpack-adapter-budget = { } lawpack-adapter-write-class = "none" / "read" / "create" / "ensure" / - "append" / "modify" / "delete" + "append" / "replace" / "delete" / "custom" ; failure-ident is defined in edict-common.cddl. @@ -789,6 +789,45 @@ authority-budget-fact = { authority-write-class = "none" / "read" / "create" / "ensure" / "append" / "replace" / "delete" / "custom" +; --- edict-result-projection.cddl --- +; SPDX-License-Identifier: Apache-2.0 +; edict-result-projection.cddl +; Canonical schema for compiler-owned application-result projections. +; Authoritative byte encoding: edict.canonical-cbor/v1. + +result-projection = { + schema: "edict.result-projection/v1", + operationCoordinate: bounded-projection-text, + outputType: bounded-projection-text, + maxOutputBytes: uint .gt 0, + expression: result-projection-expr, +} + +result-projection-expr = result-projection-record / result-projection-source + +result-projection-record = { + kind: "record", + ; The root record counts as one of the Rust decoder's 256 expression nodes. + ; Nested aggregate node count remains an authoritative decoder check. + fields: { 0*255 bounded-projection-text => result-projection-expr }, +} + +result-projection-source = { + kind: "source", + source: result-projection-source-kind, + ; Matches MAX_RESULT_PROJECTION_PATH_SEGMENTS in edict-syntax. + path: [0*32 bounded-projection-text], +} + +result-projection-source-kind = + { kind: "applicationInput" } / + { + kind: "capabilityResult", + stepId: bounded-projection-text, + } + +bounded-projection-text = tstr .size (1..1024) + ; --- edict-target-ir.cddl --- ; SPDX-License-Identifier: Apache-2.0 ; edict-target-ir.cddl @@ -1056,6 +1095,7 @@ echo-nonempty-tstr = tstr .regexp "(?s).+" edict-source-bytes = bstr echo-operation-package = { + "application_result_projection": echo-operation-application-result-projection, "application_basis_schema_identity": bstr .size 32, "authority_profile_identity": bstr .size 32, "budget_ceiling": echo-operation-budget, @@ -1076,6 +1116,28 @@ echo-operation-package = { "target_profile_identity": bstr .size 32, } +echo-operation-application-result-projection = { + "application_input_node_key_path": [* echo-nonempty-tstr], + "application_input_replacement_path": [* echo-nonempty-tstr], + "artifact_bytes": bstr, + "artifact_identity": bstr .size 32, + "runtime_expression": echo-operation-result-expression, +} + +echo-operation-result-expression = + echo-operation-result-record / echo-operation-result-source + +echo-operation-result-record = { + kind: "record", + fields: { * echo-nonempty-tstr => echo-operation-result-expression }, +} + +echo-operation-result-source = { + kind: "source", + path: [* echo-nonempty-tstr], + source: { kind: "applicationInput" }, +} + echo-operation-budget = { "read_bytes": uint, steps: 1..18446744073709551615, @@ -1115,6 +1177,7 @@ echo-operation-lowering-configuration = { echo-operation-package-verifier-report = { apiVersion: "echo.operation-package-verifier-report/v1", + applicationResultProjection: resource-ref, package: resource-ref, targetIr: resource-ref, outcome: "accepted" / "rejected", diff --git a/schemas/edict-provider/package/README.md b/schemas/edict-provider/package/README.md index 22e555c1..1c879faa 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, 30 schema bindings, and raw identities of all 24 non-manifest members. +routes, 31 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: @@ -37,7 +37,7 @@ 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 30 schema bindings, validates every canonical primary and generated +all 31 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: 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 8ba4de4e..fc90817b 100644 Binary files a/schemas/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm and b/schemas/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm differ 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 284ccec0..b6c120b0 100644 Binary files a/schemas/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm and b/schemas/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm differ 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 da7bace8..632d8807 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:e2a6a539a7156296c18ff1bc02f80dcabf62b42bb4314d0737527869e43986d6"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:ce1af559551f8b8242c4b290b620c5a28323b9e43f8bc6bb161a191001b6f4b9"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:8c570362671a0b1cd1a992d8210e4a90ffd153ad06dcdf1e0cb36033cc971e2c"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:1b105d1b1f6cdf5fecdef98b7adeb238525047d43581fe9fd8c44fd213e1788e"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:6b9076ae02730797fddf60a93606df3de245a1c6bfbd845486799b7310d002a2"}],"generationInputDigest":"sha256:49646ba46efe7b070ff1605bf7b148e6d35611a570015e9b08fa7d30206ec7c7","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:a5d5ea82a9e64aa78c4a44204d3e8919c1c590febb967f1d31639fdc2a20a96c"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:f78dc8bb32f04f3e246f57e4228077c2a243827dd243525b9bd2e1d81dfa07ff"}]} \ 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:e2a6a539a7156296c18ff1bc02f80dcabf62b42bb4314d0737527869e43986d6"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:ce1af559551f8b8242c4b290b620c5a28323b9e43f8bc6bb161a191001b6f4b9"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:8c570362671a0b1cd1a992d8210e4a90ffd153ad06dcdf1e0cb36033cc971e2c"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:1b105d1b1f6cdf5fecdef98b7adeb238525047d43581fe9fd8c44fd213e1788e"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:730ce72f6658fe8cc9302221c32ad5992492e190674ddd69c1b164749d2bb669"}],"generationInputDigest":"sha256:57f5f67172544014af9c92e658301b9fcec69fd77fba9d251b258b59e3591380","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:ff5405708185e0bcf33dac263000fcb772c79e21145ad69da7cad0692e1a9552"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:e31d0452bf9d8ba84eaa1ce8c09fa1c25f740decd0ab08cd9c2fde533bdef1fa"}]} \ 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 e333e6dc..0ba69ca3 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:e2a6a539a7156296c18ff1bc02f80dcabf62b42bb4314d0737527869e43986d6"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:ce1af559551f8b8242c4b290b620c5a28323b9e43f8bc6bb161a191001b6f4b9"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:8c570362671a0b1cd1a992d8210e4a90ffd153ad06dcdf1e0cb36033cc971e2c"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:1b105d1b1f6cdf5fecdef98b7adeb238525047d43581fe9fd8c44fd213e1788e"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:6b9076ae02730797fddf60a93606df3de245a1c6bfbd845486799b7310d002a2"}],"generationInputDigest":"sha256:49646ba46efe7b070ff1605bf7b148e6d35611a570015e9b08fa7d30206ec7c7","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52","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:d448084da79f0cca20fa538f188e414d37192be88b127facc0056a4571da7741","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:a5d5ea82a9e64aa78c4a44204d3e8919c1c590febb967f1d31639fdc2a20a96c"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:f78dc8bb32f04f3e246f57e4228077c2a243827dd243525b9bd2e1d81dfa07ff"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:e2a6a539a7156296c18ff1bc02f80dcabf62b42bb4314d0737527869e43986d6"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:ce1af559551f8b8242c4b290b620c5a28323b9e43f8bc6bb161a191001b6f4b9"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:8c570362671a0b1cd1a992d8210e4a90ffd153ad06dcdf1e0cb36033cc971e2c"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:1b105d1b1f6cdf5fecdef98b7adeb238525047d43581fe9fd8c44fd213e1788e"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:730ce72f6658fe8cc9302221c32ad5992492e190674ddd69c1b164749d2bb669"}],"generationInputDigest":"sha256:57f5f67172544014af9c92e658301b9fcec69fd77fba9d251b258b59e3591380","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346","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:998426658fbcbd44bff4f28d0d4c82df7aaf05bdbcdb736db9cf481a1948ec82","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:ff5405708185e0bcf33dac263000fcb772c79e21145ad69da7cad0692e1a9552"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:e31d0452bf9d8ba84eaa1ce8c09fa1c25f740decd0ab08cd9c2fde533bdef1fa"}]} \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl b/schemas/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl index 32ecdc59..ea161b3d 100644 --- a/schemas/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl +++ b/schemas/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl @@ -583,7 +583,7 @@ lawpack-adapter-budget = { } lawpack-adapter-write-class = "none" / "read" / "create" / "ensure" / - "append" / "modify" / "delete" + "append" / "replace" / "delete" / "custom" ; failure-ident is defined in edict-common.cddl. @@ -789,6 +789,45 @@ authority-budget-fact = { authority-write-class = "none" / "read" / "create" / "ensure" / "append" / "replace" / "delete" / "custom" +; --- edict-result-projection.cddl --- +; SPDX-License-Identifier: Apache-2.0 +; edict-result-projection.cddl +; Canonical schema for compiler-owned application-result projections. +; Authoritative byte encoding: edict.canonical-cbor/v1. + +result-projection = { + schema: "edict.result-projection/v1", + operationCoordinate: bounded-projection-text, + outputType: bounded-projection-text, + maxOutputBytes: uint .gt 0, + expression: result-projection-expr, +} + +result-projection-expr = result-projection-record / result-projection-source + +result-projection-record = { + kind: "record", + ; The root record counts as one of the Rust decoder's 256 expression nodes. + ; Nested aggregate node count remains an authoritative decoder check. + fields: { 0*255 bounded-projection-text => result-projection-expr }, +} + +result-projection-source = { + kind: "source", + source: result-projection-source-kind, + ; Matches MAX_RESULT_PROJECTION_PATH_SEGMENTS in edict-syntax. + path: [0*32 bounded-projection-text], +} + +result-projection-source-kind = + { kind: "applicationInput" } / + { + kind: "capabilityResult", + stepId: bounded-projection-text, + } + +bounded-projection-text = tstr .size (1..1024) + ; --- edict-target-ir.cddl --- ; SPDX-License-Identifier: Apache-2.0 ; edict-target-ir.cddl @@ -1056,6 +1095,7 @@ echo-nonempty-tstr = tstr .regexp "(?s).+" edict-source-bytes = bstr echo-operation-package = { + "application_result_projection": echo-operation-application-result-projection, "application_basis_schema_identity": bstr .size 32, "authority_profile_identity": bstr .size 32, "budget_ceiling": echo-operation-budget, @@ -1076,6 +1116,28 @@ echo-operation-package = { "target_profile_identity": bstr .size 32, } +echo-operation-application-result-projection = { + "application_input_node_key_path": [* echo-nonempty-tstr], + "application_input_replacement_path": [* echo-nonempty-tstr], + "artifact_bytes": bstr, + "artifact_identity": bstr .size 32, + "runtime_expression": echo-operation-result-expression, +} + +echo-operation-result-expression = + echo-operation-result-record / echo-operation-result-source + +echo-operation-result-record = { + kind: "record", + fields: { * echo-nonempty-tstr => echo-operation-result-expression }, +} + +echo-operation-result-source = { + kind: "source", + path: [* echo-nonempty-tstr], + source: { kind: "applicationInput" }, +} + echo-operation-budget = { "read_bytes": uint, steps: 1..18446744073709551615, @@ -1115,6 +1177,7 @@ echo-operation-lowering-configuration = { echo-operation-package-verifier-report = { apiVersion: "echo.operation-package-verifier-report/v1", + applicationResultProjection: resource-ref, package: resource-ref, targetIr: resource-ref, outcome: "accepted" / "rejected", diff --git a/schemas/edict-provider/package/v1/provider-manifest.echo.json b/schemas/edict-provider/package/v1/provider-manifest.echo.json index 4fabbf1c..729f3463 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:a7ab6bfbbedc3a6b61a8559dc6506cfc3d2836b46dac3cc825e5b05b16b94fa5" + "digest": "sha256:fe1a1f1c05e88bb3caeadb2d77fb17a906a4819674c50d75b2dcaca0fb6058ec" }, "artifacts": [ { @@ -17,11 +17,11 @@ "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070" + "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52" + "digest": "sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346" } } }, @@ -36,11 +36,11 @@ "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070" + "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52" + "digest": "sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346" } } }, @@ -55,11 +55,11 @@ "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070" + "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52" + "digest": "sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346" } } }, @@ -74,11 +74,11 @@ "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070" + "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52" + "digest": "sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346" } } }, @@ -87,13 +87,13 @@ "artifactKind": "lowerer", "resource": { "coordinate": "echo.dpo.lowerer/component@1", - "digest": "sha256:08277d4ba7d98e0b143c06c208abc306f133bda510caa5393da08aa490334a6e" + "digest": "sha256:dfd14015705ff555a7efdb3787ddb0f8b4f304168a9a0ebf324fd25d430bf5cd" }, "source": { "kind": "component", "component": { "coordinate": "echo.dpo.lowerer/component@1", - "digest": "sha256:08277d4ba7d98e0b143c06c208abc306f133bda510caa5393da08aa490334a6e" + "digest": "sha256:dfd14015705ff555a7efdb3787ddb0f8b4f304168a9a0ebf324fd25d430bf5cd" } } }, @@ -102,17 +102,17 @@ "artifactKind": "generationProvenance", "resource": { "coordinate": "echo.edict-provider-generation-provenance@1", - "digest": "sha256:83840aab907b1189482a92f70a405602bf76715dc8e4fbffdc543db2d6151019" + "digest": "sha256:720076fdd6462ab5500e944408199a141d07eca8e4e73d542e01e7fcdc715ac4" }, "source": { "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070" + "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52" + "digest": "sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346" } } }, @@ -121,17 +121,17 @@ "artifactKind": "reviewArtifact", "resource": { "coordinate": "echo.edict-provider-generation-review@1", - "digest": "sha256:26b954ae9e2220a339c2dfb6673615aafb1567be19aa7ee38eefa6b34e18897d" + "digest": "sha256:592af76dab9f354a4afb663365990e8a14bf07c1721cdc2242319ad457ee5e2b" }, "source": { "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070" + "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52" + "digest": "sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346" } } }, @@ -140,17 +140,17 @@ "artifactKind": "artifactSchema", "resource": { "coordinate": "echo.provider-artifacts.cddl@1", - "digest": "sha256:6b9076ae02730797fddf60a93606df3de245a1c6bfbd845486799b7310d002a2" + "digest": "sha256:730ce72f6658fe8cc9302221c32ad5992492e190674ddd69c1b164749d2bb669" }, "source": { "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070" + "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52" + "digest": "sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346" } } }, @@ -165,11 +165,11 @@ "kind": "generated", "semanticSource": { "coordinate": "echo.semantic-schema@1", - "digest": "sha256:3a11315cb8aa1484ac73c44e725a50faa9ba696dcd8ca8a41a924a2810835070" + "digest": "sha256:322d9eb5eb8273108eaa602f2eb58ba591efcf829fecb10bb705717efae18852" }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4222f5b0950a8af9642894d651113283350e0d9d7a32559e80912d9d2dd76b52" + "digest": "sha256:434467463d311ae5df7b3f778b75cb19113ec31ec2b82e572316c2f788f35346" } } }, @@ -178,13 +178,13 @@ "artifactKind": "verifier", "resource": { "coordinate": "echo.dpo.verifier/component@1", - "digest": "sha256:744a511137608634b88abf7bd7e61da9bf81a5cacff7b190fc2530c346ba36cc" + "digest": "sha256:279738ffeea40027eb493c15e873b87cf3aa0677a57f9f03fb824698e532322f" }, "source": { "kind": "component", "component": { "coordinate": "echo.dpo.verifier/component@1", - "digest": "sha256:744a511137608634b88abf7bd7e61da9bf81a5cacff7b190fc2530c346ba36cc" + "digest": "sha256:279738ffeea40027eb493c15e873b87cf3aa0677a57f9f03fb824698e532322f" } } } @@ -352,6 +352,12 @@ "format": "selfContainedCddlV1", "rootRule": "lowering-requirements" }, + { + "domain": "edict.result-projection.artifact/v1", + "schemaRole": "schema.echo-provider-artifacts", + "format": "selfContainedCddlV1", + "rootRule": "result-projection" + }, { "domain": "edict.source/v1", "schemaRole": "schema.echo-provider-artifacts", diff --git a/tests/edict-provider-host-v1/Cargo.lock b/tests/edict-provider-host-v1/Cargo.lock index b279e105..c88c8b29 100644 --- a/tests/edict-provider-host-v1/Cargo.lock +++ b/tests/edict-provider-host-v1/Cargo.lock @@ -1216,6 +1216,7 @@ dependencies = [ "echo-wasm-abi", "hex", "rustc-hash", + "sha2", "thiserror 1.0.69", "warp-math", ] diff --git a/tests/edict-provider-host-v1/tests/package_contract.rs b/tests/edict-provider-host-v1/tests/package_contract.rs index 07c1a927..a78809f8 100644 --- a/tests/edict-provider-host-v1/tests/package_contract.rs +++ b/tests/edict-provider-host-v1/tests/package_contract.rs @@ -68,7 +68,7 @@ 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 PACKAGE_OBSERVATION_MARKER: &str = "ECHO_EDICT_PACKAGE_OBSERVATION="; -const EXPECTED_SCHEMA_BINDING_COUNT: usize = 30; +const EXPECTED_SCHEMA_BINDING_COUNT: usize = 31; const MANIFEST_BYTES: &[u8] = include_bytes!("../../../schemas/edict-provider/package/v1/provider-manifest.echo.json"); @@ -1763,6 +1763,11 @@ fn checked_package_is_ready_for_edict_before_guest_execution() { EXPECTED_SCHEMA_BINDING_COUNT ); assert_eq!(registry.bindings().len(), EXPECTED_SCHEMA_BINDING_COUNT); + assert_schema_binding( + &manifest, + "edict.result-projection.artifact/v1", + "result-projection", + ); assert_routed_canonical_artifacts(&manifest, ®istry); assert_generated_resources(&manifest, ®istry); let lawpack = decode_canonical_cbor(LAWPACK_BYTES).expect("lawpack is canonical"); diff --git a/xtask/src/provider_lowerer_component.rs b/xtask/src/provider_lowerer_component.rs index 982933c2..444c4bfe 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 = - "08277d4ba7d98e0b143c06c208abc306f133bda510caa5393da08aa490334a6e"; + "dfd14015705ff555a7efdb3787ddb0f8b4f304168a9a0ebf324fd25d430bf5cd"; 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 = - "744a511137608634b88abf7bd7e61da9bf81a5cacff7b190fc2530c346ba36cc"; + "279738ffeea40027eb493c15e873b87cf3aa0677a57f9f03fb824698e532322f"; #[derive(Clone, Copy, Debug, Eq, PartialEq)] struct ProviderComponentSpec { diff --git a/xtask/src/run_edict_operation.rs b/xtask/src/run_edict_operation.rs index 373a428a..5671f0f6 100644 --- a/xtask/src/run_edict_operation.rs +++ b/xtask/src/run_edict_operation.rs @@ -13,7 +13,8 @@ use anyhow::{bail, Context, Result}; use blake3::Hasher; use bytes::Bytes; use echo_edict_canonical::{ - decode_canonical_cbor_v1, digest_canonical_value_bytes_v1, CanonicalValueV1, + decode_canonical_cbor_v1, digest_canonical_value_bytes_v1, encode_canonical_cbor_v1, + CanonicalValueV1, }; use serde::Serialize; use sha2::{Digest, Sha256}; @@ -23,7 +24,7 @@ use warp_core::{ echo_operation_create_if_absent_target_profile_identity_v1, echo_operation_package_id_v1, make_head_id, make_node_id, make_type_id, make_warp_id, AtomPayload, AttachmentValue, EchoOperationActionOutcomeV1, EchoOperationAdmissionPolicyV1, - EchoOperationAnchoredNodeOccupancyV1, EchoOperationBudgetV1, + EchoOperationAnchoredNodeOccupancyV1, EchoOperationApplicationResultV1, EchoOperationBudgetV1, EchoOperationInvocationAdmissionPolicyV1, EchoOperationInvocationV1, EchoOperationObstructionKindV1, EngineBuilder, GraphStore, InboxPolicy, IngressTarget, NodeId, NodeKey, NodeRecord, PlaybackMode, SchedulerKind, TrustedRuntimeHost, TrustedRuntimeHostError, @@ -66,6 +67,7 @@ pub struct RunEdictOperationReport { pub submission: SubmissionReport, pub scheduler: SchedulerReport, pub state: StateReport, + pub application_result: ApplicationResultReport, pub recovery: RecoveryReport, pub duplicate: DuplicateReport, } @@ -118,6 +120,15 @@ pub struct StateReport { pub value_utf8: String, } +#[derive(Clone, Eq, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ApplicationResultReport { + pub projection_identity: String, + pub output_type: String, + pub canonical_bytes_hex: String, + pub result_identity: String, +} + #[derive(Serialize)] #[serde(rename_all = "camelCase")] pub struct RecoveryReport { @@ -127,6 +138,7 @@ pub struct RecoveryReport { pub state_recovered: bool, pub outcome_recovered: bool, pub receipt_recovered: bool, + pub application_result_recovered: bool, pub mutated_initial_state_refusal: &'static str, } @@ -148,6 +160,7 @@ struct PackageMetadata { authority_profile_identity: [u8; 32], target_profile_identity: [u8; 32], target_ir_identity: [u8; 32], + result_projection_identity: [u8; 32], target_intrinsic: &'static str, budget: EchoOperationBudgetV1, required_node_type: TypeId, @@ -169,6 +182,7 @@ struct OperationInput { basis: String, key: String, replacement: Vec, + canonical_bytes: Vec, } struct HostFixture { @@ -208,7 +222,13 @@ pub fn run(config: RunEdictOperationConfig) -> Result { let package_value = decode_canonical_cbor_v1(&package_bytes).context("package is not canonical Edict CBOR")?; let package = parse_package(&package_value)?; - validate_verification_report(&report_bytes, &package_value, package.target_ir_identity)?; + validate_verification_report( + &report_bytes, + &package_value, + &package.operation_coordinate, + package.target_ir_identity, + package.result_projection_identity, + )?; let target_configuration = validate_closure( &manifest_bytes, &adapter_bytes, @@ -258,6 +278,7 @@ pub fn run(config: RunEdictOperationConfig) -> Result { let receipt_digest; let commit_global_tick; let worldline_tick_after; + let application_result; { let mut fixture = build_host(&input.basis, &input.key, false)?; @@ -275,7 +296,7 @@ pub fn run(config: RunEdictOperationConfig) -> Result { &package, package_id, authority_grant_identity, - &input.replacement, + &input, EchoOperationAnchoredNodeOccupancyV1::Absent, )?; let envelope = echo_operation_action_envelope_v1( @@ -367,6 +388,11 @@ pub fn run(config: RunEdictOperationConfig) -> Result { .context("committed Action receipt has no global Tick coordinate")? .as_u64(); worldline_tick_after = committed_receipt.worldline_tick_after().as_u64(); + application_result = application_result_report( + committed_receipt + .committed_application_result() + .context("committed Action receipt has no typed application result")?, + ); let value = node_value( &pending, package.required_node_type, @@ -383,6 +409,7 @@ pub fn run(config: RunEdictOperationConfig) -> Result { let state_recovered; let outcome_recovered; let receipt_recovered; + let application_result_recovered; let duplicate; { @@ -411,21 +438,42 @@ pub fn run(config: RunEdictOperationConfig) -> Result { package.required_node_type, package.required_attachment_type, )? == input.replacement; - outcome_recovered = matches!( - recovered - .host - .echo_operation_action_outcome_v1(&first_submission_id), - Some(EchoOperationActionOutcomeV1::Committed(_)) - ); - receipt_recovered = recovered_wal.echo_operation_action_outcomes.iter().any( - |(submission_id, _, outcome)| { - *submission_id == first_submission_id - && matches!(outcome, EchoOperationActionOutcomeV1::Committed(_)) - }, - ) && recovered_wal - .receipt_correlations + let recovered_result = match recovered + .host + .echo_operation_action_outcome_v1(&first_submission_id) + { + Some(EchoOperationActionOutcomeV1::Committed(receipt)) => { + Some(application_result_report( + receipt + .committed_application_result() + .context("recovered Action outcome has no typed application result")?, + )) + } + _ => None, + }; + outcome_recovered = recovered_result.is_some(); + let wal_result = recovered_wal + .echo_operation_action_outcomes .iter() - .any(|record| record.submission_id == first_submission_id); + .find_map(|(submission_id, _, outcome)| { + (*submission_id == first_submission_id) + .then_some(outcome) + .and_then(|outcome| match outcome { + EchoOperationActionOutcomeV1::Committed(receipt) => { + receipt.committed_application_result() + } + EchoOperationActionOutcomeV1::Obstructed(_) + | EchoOperationActionOutcomeV1::RejectedFootprintConflict(_) => None, + }) + .map(application_result_report) + }); + receipt_recovered = wal_result.is_some() + && recovered_wal + .receipt_correlations + .iter() + .any(|record| record.submission_id == first_submission_id); + application_result_recovered = recovered_result.as_ref() == Some(&application_result) + && wal_result.as_ref() == Some(&application_result); recovered .host @@ -441,7 +489,7 @@ pub fn run(config: RunEdictOperationConfig) -> Result { &package, package_id, authority_grant_identity, - &input.replacement, + &input, EchoOperationAnchoredNodeOccupancyV1::NodeAndAttachment, )?; let duplicate_envelope = echo_operation_action_envelope_v1( @@ -493,6 +541,7 @@ pub fn run(config: RunEdictOperationConfig) -> Result { || !state_recovered || !outcome_recovered || !receipt_recovered + || !application_result_recovered { bail!("fresh host did not recover the complete Action/Tick/state/outcome/Receipt witness"); } @@ -545,6 +594,7 @@ pub fn run(config: RunEdictOperationConfig) -> Result { value_utf8: String::from_utf8(input.replacement) .context("replacement value is not UTF-8")?, }, + application_result, recovery: RecoveryReport { pending_action_recovered, action_recovered, @@ -552,6 +602,7 @@ pub fn run(config: RunEdictOperationConfig) -> Result { state_recovered, outcome_recovered, receipt_recovered, + application_result_recovered, mutated_initial_state_refusal, }, duplicate, @@ -593,6 +644,15 @@ fn artifact_identity(digest_hex: String) -> ArtifactIdentity { } } +fn application_result_report(result: &EchoOperationApplicationResultV1) -> ApplicationResultReport { + ApplicationResultReport { + projection_identity: hex::encode(result.projection_identity()), + output_type: result.output_type().to_owned(), + canonical_bytes_hex: hex::encode(result.canonical_bytes()), + result_identity: hex::encode(result.identity()), + } +} + fn read_bounded(path: &Path, maximum: u64, label: &str) -> Result> { let file = File::open(path).with_context(|| format!("failed to open {label} {}", path.display()))?; @@ -617,6 +677,7 @@ fn read_bounded(path: &Path, maximum: u64, label: &str) -> Result> { fn parse_package(value: &CanonicalValueV1) -> Result { require_text(value, "schema", "package", "echo.operation-package/v1")?; + let result_projection = map_field(value, "application_result_projection", "package")?; let program_bytes = bytes_field(value, "program", "package")?; let program = decode_canonical_cbor_v1(program_bytes).context("package program is not canonical")?; @@ -648,6 +709,11 @@ fn parse_package(value: &CanonicalValueV1) -> Result { authority_profile_identity: hash_field(value, "authority_profile_identity", "package")?, target_profile_identity: hash_field(value, "target_profile_identity", "package")?, target_ir_identity: hash_field(semantic_closure, "target_ir_identity", "semantic closure")?, + result_projection_identity: hash_field( + result_projection, + "artifact_identity", + "application result projection", + )?, target_intrinsic, budget: budget_value( budget, @@ -680,7 +746,9 @@ fn target_intrinsic_for_program_kind(program_kind: &str) -> Result<&'static str> fn validate_verification_report( bytes: &[u8], package: &CanonicalValueV1, + operation_coordinate: &str, expected_target_ir_identity: [u8; 32], + expected_result_projection_identity: [u8; 32], ) -> Result<()> { let report = decode_canonical_cbor_v1(bytes) .context("verification report is not canonical Edict CBOR")?; @@ -696,6 +764,15 @@ fn validate_verification_report( } let package_ref = map_field(&report, "package", "verification report")?; validate_resource_ref(package_ref, PACKAGE_ROLE, PACKAGE_DOMAIN, package)?; + let result_projection = map_field( + &report, + "applicationResultProjection", + "verification report", + )?; + require_resource_identity(result_projection, operation_coordinate)?; + if resource_digest(result_projection)? != expected_result_projection_identity { + bail!("verification report does not bind the package application-result projection"); + } let target_ir = map_field(&report, "targetIr", "verification report")?; require_resource_identity(target_ir, TARGET_IR_COORDINATE)?; if resource_digest(target_ir)? != expected_target_ir_identity { @@ -865,6 +942,13 @@ fn parse_input(bytes: &[u8], configuration: &TargetConfiguration) -> Result MAX_INPUT_BYTES { + bail!("canonical operation input exceeds the host byte bound"); + } let object = value .as_object() .context("operation input must be one JSON object")?; @@ -900,9 +984,51 @@ fn parse_input(bytes: &[u8], configuration: &TargetConfiguration) -> Result Result { + *nodes = nodes + .checked_add(1) + .context("operation input node count overflowed")?; + if *nodes > 4_096 { + bail!("operation input exceeds the canonical value-node bound"); + } + match value { + serde_json::Value::Null => Ok(CanonicalValueV1::Null), + serde_json::Value::Bool(value) => Ok(CanonicalValueV1::Bool(*value)), + serde_json::Value::Number(value) => value + .as_u64() + .map(|value| CanonicalValueV1::Integer(i128::from(value))) + .or_else(|| { + value + .as_i64() + .map(|value| CanonicalValueV1::Integer(i128::from(value))) + }) + .context("operation input numbers must be integers"), + serde_json::Value::String(value) => Ok(CanonicalValueV1::Text(value.clone())), + serde_json::Value::Array(values) => values + .iter() + .map(|value| canonical_application_input(value, nodes)) + .collect::>>() + .map(CanonicalValueV1::Array), + serde_json::Value::Object(values) => values + .iter() + .map(|(key, value)| { + Ok(( + CanonicalValueV1::Text(key.clone()), + canonical_application_input(value, nodes)?, + )) + }) + .collect::>>() + .map(CanonicalValueV1::Map), + } +} + fn install_package( host: &mut TrustedRuntimeHost, package: &PackageMetadata, @@ -996,7 +1122,7 @@ fn invocation( package: &PackageMetadata, package_id: warp_core::EchoOperationPackageIdV1, authority_grant_identity: [u8; 32], - replacement: &[u8], + input: &OperationInput, occupancy: EchoOperationAnchoredNodeOccupancyV1, ) -> Result> { let application_basis = @@ -1004,14 +1130,15 @@ fn invocation( let evaluation_basis = fixture .host .echo_operation_evaluation_basis_v1(fixture.head, application_basis)?; - EchoOperationInvocationV1::anchored_node_attachment_create_if_absent( + EchoOperationInvocationV1::anchored_node_attachment_create_if_absent_with_application_input( package_id, &package.operation_coordinate, evaluation_basis, authority_grant_identity, package.budget, fixture.node, - replacement.to_vec(), + input.replacement.clone(), + input.canonical_bytes.clone(), ) .to_canonical_bytes() .context("failed to encode canonical executable-operation invocation") diff --git a/xtask/tests/fixtures/edict-operation/ORIGIN.toml b/xtask/tests/fixtures/edict-operation/ORIGIN.toml index ffdb6d47..95716b16 100644 --- a/xtask/tests/fixtures/edict-operation/ORIGIN.toml +++ b/xtask/tests/fixtures/edict-operation/ORIGIN.toml @@ -2,18 +2,18 @@ # © James Ross Ω FLYING•ROBOTS schema = "echo.edict-operation-fixture-origin/v1" repository = "https://github.com/flyingrobots/hello-echo" -commit = "8dd96de482ffee8fa6efb2ebe508f649e1d878a7" -edict_commit = "296bf1f6c76af1e011f5214b6d3de260c67ca84a" -echo_commit = "f324ae18226f685fe8ff2f3f6c57d2592fbd0c1d" +commit = "f93e2ffdb707c0bf56eab41dc5a06d0fac51d344" +edict_commit = "21c4400faadf107e68906463d67c95532563c2ed" +echo_commit = "30e23bf4abd55ff06027c2ba004b169da10d8965" build_command = "EDICT_REPO= ECHO_REPO= ./tests/build.sh" [artifacts.executable_operation_package] path = ".build/application/executable-operation-package.cbor" -sha256 = "67dc6d23e223e78b6aa774a2f57c86db2eff4981ea793975d39c66f731f02fd1" +sha256 = "3665d692cdd120f116f18067f2fd583e841448d057b5e35515f57264f853d0f6" [artifacts.verification_report] path = ".build/application/verification-report.cbor" -sha256 = "8a5153b4ec25ebe979f0ceab373d03969e30a64d7973b3a83e3c84877c5aa564" +sha256 = "2541c8263d95fdad52f4f5a3bbfed48fdefd9f20969156c3c3fd56be912b66dd" [artifacts.lawpack_manifest] path = "vendor/causal-cell/manifest.cbor" diff --git a/xtask/tests/fixtures/edict-operation/executable-operation-package.cbor b/xtask/tests/fixtures/edict-operation/executable-operation-package.cbor index e6d4d055..66daea8d 100644 Binary files a/xtask/tests/fixtures/edict-operation/executable-operation-package.cbor and b/xtask/tests/fixtures/edict-operation/executable-operation-package.cbor differ diff --git a/xtask/tests/fixtures/edict-operation/verification-report.cbor b/xtask/tests/fixtures/edict-operation/verification-report.cbor index df5a2d02..b6310a85 100644 Binary files a/xtask/tests/fixtures/edict-operation/verification-report.cbor and b/xtask/tests/fixtures/edict-operation/verification-report.cbor differ diff --git a/xtask/tests/run_edict_operation.rs b/xtask/tests/run_edict_operation.rs index 1a156f1a..8c2e7b40 100644 --- a/xtask/tests/run_edict_operation.rs +++ b/xtask/tests/run_edict_operation.rs @@ -160,7 +160,7 @@ fn compiler_emitted_operation_runs_durably_without_native_callbacks() { assert_eq!(report["artifacts"]["package"]["algorithm"], "sha256"); assert_eq!( report["artifacts"]["package"]["digestHex"], - "67dc6d23e223e78b6aa774a2f57c86db2eff4981ea793975d39c66f731f02fd1" + "3665d692cdd120f116f18067f2fd583e841448d057b5e35515f57264f853d0f6" ); assert_eq!( report["artifacts"]["verificationReport"]["algorithm"], @@ -168,7 +168,7 @@ fn compiler_emitted_operation_runs_durably_without_native_callbacks() { ); assert_eq!( report["artifacts"]["verificationReport"]["digestHex"], - "8a5153b4ec25ebe979f0ceab373d03969e30a64d7973b3a83e3c84877c5aa564" + "2541c8263d95fdad52f4f5a3bbfed48fdefd9f20969156c3c3fd56be912b66dd" ); assert_eq!( report["artifacts"]["lawpackManifest"]["algorithm"], @@ -206,12 +206,29 @@ fn compiler_emitted_operation_runs_durably_without_native_callbacks() { assert_eq!(report["submission"]["walCommittedBeforeAck"], true); assert_eq!(report["scheduler"]["actionCount"], 1); assert_eq!(report["state"]["valueUtf8"], "Hello Echo"); + assert_eq!( + report["applicationResult"]["projectionIdentity"], + "791fb36bb4d42273eb558ce4d03d68d90a678d15891fb9cbe4ad8a20bb56fa82" + ); + assert_eq!( + report["applicationResult"]["outputType"], + "examples.hello_echo@1.GreetingCreated" + ); + assert_eq!( + report["applicationResult"]["canonicalBytesHex"], + "a2636b6579686772656574696e67676d6573736167656a48656c6c6f204563686f" + ); + assert_eq!( + report["applicationResult"]["resultIdentity"], + "bfc50f30e68ac57742ef0fb0ccc41506c1af4a9ecdeca32c0b934a1adccb9860" + ); assert_eq!(report["recovery"]["pendingActionRecovered"], true); assert_eq!(report["recovery"]["actionRecovered"], true); assert_eq!(report["recovery"]["tickRecovered"], true); assert_eq!(report["recovery"]["stateRecovered"], true); assert_eq!(report["recovery"]["outcomeRecovered"], true); assert_eq!(report["recovery"]["receiptRecovered"], true); + assert_eq!(report["recovery"]["applicationResultRecovered"], true); assert_eq!( report["duplicate"]["obstruction"], "causal.cell@1.AlreadyExists" @@ -375,6 +392,74 @@ fn verification_report_target_ir_must_match_the_package_semantic_closure() { ); } +#[test] +fn verification_report_must_bind_the_compiler_result_projection() { + let run_dir = TempRunDir::new(); + let report_path = run_dir.path().join("result-projection-substitution.cbor"); + let mut report = decode_fixture("verification-report.cbor"); + let result_projection = map_field_mut(&mut report, "applicationResultProjection"); + resource_digest_mut(result_projection)[0] ^= 0xff; + fs::write( + &report_path, + encode_canonical_cbor_v1(&report).expect("the substituted report re-encodes"), + ) + .expect("the substituted report is writable"); + + let output = runner_command( + &fixture_path("executable-operation-package.cbor"), + &report_path, + &fixture_path("input.json"), + &run_dir.path().join("result-projection-substitution-wal"), + ) + .output() + .expect("the result-projection substitution case starts"); + assert_rejected( + &output, + "verification report does not bind the package application-result projection", + ); +} + +#[test] +fn corrupted_result_projection_bytes_fail_echo_package_admission() { + let run_dir = TempRunDir::new(); + let package_path = run_dir + .path() + .join("corrupt-result-projection-package.cbor"); + let report_path = run_dir.path().join("corrupt-result-projection-report.cbor"); + + let mut package = decode_fixture("executable-operation-package.cbor"); + let projection = map_field_mut(&mut package, "application_result_projection"); + bytes_field_mut(projection, "artifact_bytes")[0] ^= 0xff; + fs::write( + &package_path, + encode_canonical_cbor_v1(&package).expect("the corrupted package re-encodes"), + ) + .expect("the corrupted package is writable"); + + let package_digest = digest_canonical_value_bytes_v1("echo.operation-package/v1", &package) + .expect("the rebound package identity is computable"); + let mut report = decode_fixture("verification-report.cbor"); + resource_digest_mut(map_field_mut(&mut report, "package")).copy_from_slice(&package_digest); + fs::write( + &report_path, + encode_canonical_cbor_v1(&report).expect("the rebound report re-encodes"), + ) + .expect("the rebound report is writable"); + + let output = runner_command( + &package_path, + &report_path, + &fixture_path("input.json"), + &run_dir.path().join("corrupt-result-projection-wal"), + ) + .output() + .expect("the corrupted projection case starts"); + assert_rejected( + &output, + "Echo independently refused the compiler-produced package", + ); +} + #[test] fn target_configuration_must_belong_to_the_selected_effect() { let run_dir = TempRunDir::new(); @@ -506,6 +591,22 @@ fn fixed_seed_keys_preserve_the_generic_durable_witness_under_bounded_stress() { assert_eq!(report["state"]["valueUtf8"], replacement); assert_eq!(report["causalSite"]["basis"], format!("basis-{index}")); assert_eq!(report["causalSite"]["nodeKey"], format!("key-{state:016x}")); + assert_eq!( + report["applicationResult"]["outputType"], + "examples.hello_echo@1.GreetingCreated" + ); + assert_eq!(report["recovery"]["applicationResultRecovered"], true); + let result = decode_canonical_cbor_v1( + &hex::decode( + report["applicationResult"]["canonicalBytesHex"] + .as_str() + .expect("application result bytes are hexadecimal"), + ) + .expect("application result bytes use valid hexadecimal"), + ) + .expect("application result bytes remain canonical"); + assert_eq!(text_field(&result, "key"), format!("key-{state:016x}")); + assert_eq!(text_field(&result, "message"), replacement); assert!( retained_receipts.insert( report["causalSite"]["receiptDigest"] @@ -536,6 +637,21 @@ fn map_field_mut<'a>(value: &'a mut CanonicalValueV1, name: &str) -> &'a mut Can .unwrap_or_else(|| panic!("fixture map is missing {name}")) } +fn text_field<'a>(value: &'a CanonicalValueV1, name: &str) -> &'a str { + let CanonicalValueV1::Map(entries) = value else { + panic!("fixture value must be a canonical map"); + }; + entries + .iter() + .find_map(|(key, value)| match (key, value) { + (CanonicalValueV1::Text(key), CanonicalValueV1::Text(value)) if key == name => { + Some(value.as_str()) + } + _ => None, + }) + .unwrap_or_else(|| panic!("fixture map is missing text field {name}")) +} + fn array_field_mut<'a>( value: &'a mut CanonicalValueV1, name: &str,