Skip to content

Implement the Echo Target IR semantic verifier#673

Open
flyingrobots wants to merge 13 commits into
mainfrom
provider/654-semantic-verifier
Open

Implement the Echo Target IR semantic verifier#673
flyingrobots wants to merge 13 commits into
mainfrom
provider/654-semantic-verifier

Conversation

@flyingrobots

@flyingrobots flyingrobots commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add Echo's pure implementation of the frozen Edict verifier world, edict:target-provider/verifier@1.0.0, for the first checked Echo DPO provider closure.
  • Independently compare exact digest-bound Core and Target IR artifacts under the exact target profile and semantic-resource closure; do not trust the lowerer's construction.
  • Reproducibly build, attest, audit, and check in the exact verifier component, then exercise accepted, semantically rejected, and typed-refusal outcomes through the pinned Edict host.
  • Keep provider semantic evidence separate from Echo runtime authority.

Closes #654.
Refs #650.

Plain-English architecture walkthrough

  1. The verifier receives only explicit values: a bound Core artifact, target profile, Target IR artifact, four ordered semantic inputs, one requested verifier-report output, and response limits. The native decision is pure and has no filesystem, environment, registry, network, clock, entropy, process, or ambient host callback.
  2. Before comparing semantics, it checks canonical CBOR and domain-framed identities, admits the exact packaged semantic resources, and verifies their relationships: target profile, intrinsic, footprint algebra, operation profile, obstruction taxonomy, lawpack adapter, lowerability facts, and verifier contract.
  3. It derives the expected first Target IR directly from the supplied Core. An exact relation returns a canonical accepted report. A schema-valid but semantically false relation returns a successful rejected report with a stable diagnostic. Unsupported or malformed closure/output claims fail closed as typed provider refusals.
  4. Those dispositions remain distinct across the WIT and host boundary. Accepted and well-formed rejected reports are schema-admitted after invocation and receive host-authored output manifests. A typed refusal has neither a successful response nor an output manifest.
  5. The report binds the exact caller-supplied Target IR occurrence reference. The host-authored manifest separately binds the Core, profile, Target IR, semantic inputs, requested output, returned bytes, and domain-framed output digest. Neither proposition claims package installation or runtime execution.
  6. The component vendors the exact frozen Edict verifier WIT, exports only the reviewed verifier function, carries the exact digest-covered contract attestation, and has no ambient imports.
  7. Two independently provisioned designated linux/amd64 builders produced byte-identical candidates. Promotion requires distinct non-aliased files, exact equality, the approved SHA-256, and a full component audit. CI repeats that two-candidate proposition.
  8. The pinned Edict c75 host preflights request artifacts and the declared output schema, invokes the checked component, validates returned reports, authors manifests, replays complete outcomes in fresh Wasmtime stores, and reproduces the same stable observations in separate OS processes.

Bounded closure and refusal posture

This PR verifies one exact effectful closure, not arbitrary future Target IR:

  • The authored Core has an empty pre-effect guard sequence, so its valid ordering is unique. Any nonempty target requirement is an introduced claim and is rejected.
  • The precommit-atomic posture and target.replace.footprint obligation are bound transitively through the exact target profile, lowerability facts, intrinsic, and echo.dpo.footprint/v1 algebra. The current Target IR has no independent footprint-expression field; this PR does not claim a generalized expression proof.
  • If a later closure admits nonempty guards or an independent footprint field, that expansion must add permutation and expression-level witnesses.
  • Unsupported read semantics remain typed refusals. Reads are not represented as synthetic mutations.
  • Target IR occurrence coordinates remain caller-bound; the report preserves the exact coordinate and digest. The fixed inner Echo semantic domain is echo.span-ir/v1, while the outer provider artifact domain is edict.target-ir.artifact/v1.
  • The frozen WIT makes response-limit overflow host-owned. The provider emits one fixed bounded result and remains invariant under limit changes; it does not truncate, reorder, substitute, or change result arms to fit.

Checked component identity

  • Bytes: 183,513
  • SHA-256: 61c833dddb1919a4b92b55b984baf01116b82f6b7d6dc23760b7ecba01dc52c9
  • Designated builder: pinned linux/amd64 / x86_64-unknown-linux-gnu Rust 1.90 toolchain
  • Output: schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm

The AMD64 builder is intentional. The component target is portable Wasm; the host architecture pin establishes one reproducible compiler environment and does not make the component AMD64-only.

Dependency rationale

  • The native verifier depends on the released workspace echo-edict-canonical leaf for the exact canonical-CBOR and domain-framed digest contracts.
  • The wasm-only adapter pins wit-bindgen =0.58.0, matching the existing lowerer toolchain and adding no new third-party dependency graph to Cargo.lock.
  • The isolated host witness pins Edict crates to exact revision c75c3f550d049485ba00eae0dc272c6dd6aca11f so the tested admission contract cannot drift.
  • There are no sibling-path dependencies, runtime discovery dependencies, or changes to Wesley in this PR.

RED / GREEN evidence

Native semantic verifier:

cargo +1.90.0 test -p echo-edict-provider-verifier --all-targets

The focused REDs began with the absent verifier implementation and then exercised unsupported intrinsic, changed budget, obstruction disagreement, introduced claims, silent loss, malformed-but-decodable Target IR, recursive discriminator handling, semantic-resource contradictions, and output overclaim. GREEN is 6 unit tests plus 19 verifier contract tests.

Actual Edict host crossing:

CARGO_TARGET_DIR=target/edict-provider-host-v1 cargo +1.94.0 test   --manifest-path tests/edict-provider-host-v1/Cargo.toml   --locked   --test host_contract

The first RED failed because echo_verifier_harness did not exist. The next admission RED exposed an out-of-order schema domain and was fixed without weakening Edict's ordering law. GREEN is 18 passed and 2 intentional ignored child entrypoints, including accepted, semantic-rejected, typed-refusal, fresh-store replay, and separate-process equality.

Cross-process review finding:

cargo +1.94.0 test   --manifest-path tests/edict-provider-host-v1/Cargo.toml   --locked   --test host_contract   independent_processes_reproduce_the_same_echo_verifier_observation   -- --exact

RED was E0425 for the absent echo_verifier_observation witness. GREEN is 1 passed, with accepted, rejected, and refused observations produced in two independent OS processes.

Local route review findings:

bash tests/hooks/test_verify_local.sh
  • Initial verifier routing RED: PASS 139 / FAIL 11.
  • Verifier routing GREEN: PASS 150 / FAIL 0.
  • Shared component-builder routing RED: PASS 150 / FAIL 4.
  • Final GREEN: PASS 154 / FAIL 0.

Component and policy witnesses:

cargo +1.90.0 test -p xtask
cargo xtask provider-verifier-component audit   --input schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm
BAN_GLOBALS_PATHS=crates/echo-edict-provider-verifier ./scripts/ban-globals.sh
DETERMINISM_PATHS=crates/echo-edict-provider-verifier ./scripts/ban-nondeterminism.sh

Results: 129 xtask tests passed; component audit matched the approved SHA and no-import topology; both targeted policy scans passed.

Final branch gate under the supported Node line:

mise exec node@24.12.0 -- pnpm install --frozen-lockfile
mise exec node@24.12.0 -- cargo xtask pr-preflight --full

All seven preflight checks passed. The full local verifier ran eight fresh lanes, including strict native and wasm Clippy plus the complete pinned Edict-host witness.

Compatibility notes

  • Adds a new workspace package and checked component; it does not remove or rename an existing Echo API.
  • The WIT adapter is byte-pinned to the frozen Edict verifier contract.
  • Provider reports and authority-facts artifacts are semantic evidence, not Echo runtime authority.
  • No provider package is installed, scheduled, executed, committed, observed, or receipted by this PR.
  • The next package goalpost must still bind exact components, semantic artifacts, profiles, schemas, and provenance into a digest-locked package.
  • No Jim-specific checkpoint, rope, causal-anchor, editor, or handwritten adapter semantics are introduced.

Documentation impact

Updated:

  • CHANGELOG.md
  • crates/echo-edict-provider-verifier/README.md
  • schemas/edict-provider/README.md
  • schemas/edict-provider/components/v1/README.md
  • docs/architecture/application-contract-hosting.md

These documents separate component identity, semantic verification, Edict-host admission/replay, package identity, and Echo runtime authority as distinct propositions.

Review

  • Strict self-review: clean.
  • Independent semantic/evidence review: clean, no P0-P2 findings.
  • Independent CI/reproducibility review: clean; its sole P3 local-routing finding was closed with RED/GREEN.
  • Final Code Lawyer: clean, zero P0-P3 findings.

Summary by CodeRabbit

  • New Features

    • Added an Edict provider verifier that checks Core and Target IR consistency and produces deterministic verification reports or structured refusals.
    • Added a WebAssembly verifier component and support for building, auditing, promoting, and reproducing it.
    • Added pinned semantic resources, target profiles, and verification fixtures.
  • Documentation

    • Documented verifier behavior, boundaries, outputs, and integration with provider hosting.
  • Tests

    • Added comprehensive contract, replay determinism, resource synchronization, and validation coverage.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds the echo-edict-provider-verifier crate and WIT world, implements deterministic Core-to-Target IR semantic verification with pinned CBOR resources, wires WASM build/audit/promotion tooling, and extends host tests, local gates, CI, reproducibility evidence, and documentation.

Changes

Verifier implementation

Layer / File(s) Summary
Contract and semantic resources
crates/echo-edict-provider-verifier/wit/*, crates/echo-edict-provider-verifier/resources/*, crates/echo-edict-provider-verifier/Cargo.toml
Defines the verifier protocol, ABI data model, packaged CBOR resource closure, and crate configuration.
Semantic admission and verification
crates/echo-edict-provider-verifier/src/lib.rs, src/semantic_resources.rs, tests/verifier_contract.rs
Validates pinned resources, artifact bindings, Core and Target IR structure, expression shapes, relation exactness, deterministic reports, and typed refusals.
WASM guest adapter
crates/echo-edict-provider-verifier/src/component.rs
Maps WIT requests and results to the Rust verifier model and exports the verifier component world.
Component tooling
xtask/src/main.rs, xtask/src/provider_lowerer_component.rs
Adds verifier build, check, audit, identity, reproducibility, output synchronization, and promotion flows while sharing lowerer tooling.
Host and CI integration
.github/workflows/*, scripts/*, tests/edict-provider-host-v1/*, tests/hooks/*
Adds verifier component CI, reproducibility evidence, host admission/replay tests, resource synchronization, local routing, and wasm Clippy coverage.
Documentation and policy
CHANGELOG.md, docs/architecture/*, schemas/edict-provider/*, det-policy.yaml
Documents verifier behavior, component promotion, authority boundaries, and critical determinism coverage.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related issues

Possibly related PRs

  • flyingrobots/echo#672 — Provides the lowerer component machinery that this change generalizes for verifier components.
  • flyingrobots/echo#283 — Introduced the determinism-gate evidence flow extended here for verifier artifacts.
  • flyingrobots/echo#302 — Introduced local verification routing extended here for the verifier crate.

Suggested labels: security

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive Most #654 criteria are covered, but schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm is excluded by !**/*.wasm, so the exact attestation/import set can't be verified. Expose schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm to review or provide its digest/import manifest so the verifier bytes can be checked.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and matches the main change: adding the Echo Target IR semantic verifier.
Out of Scope Changes check ✅ Passed The changes stay on-scope for the verifier component and its supporting tests, docs, workflows, scripts, and resources.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch provider/654-semantic-verifier

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 216-218: Update the actions/checkout@v4 step to explicitly disable
credential persistence by setting persist-credentials to false in its with
configuration, while preserving the existing submodules setting.

In `@crates/echo-edict-provider-verifier/src/lib.rs`:
- Around line 689-713: Update preflight_expr and validate_target_expr_shape to
fully validate the structure and nesting depth of known Target IR variants,
including variant, match, list, map, and if, before classifying unsupported
semantics as Err(Unsupported). Reuse the same validation for requirement
predicates and onFailure handlers instead of accepting arbitrary maps, so
malformed expressions such as an if without required fields return
InvalidSemanticArtifact rather than a successful rejected report.

In `@crates/echo-edict-provider-verifier/src/semantic_resources.rs`:
- Around line 178-247: Update validate_references to validate the profile’s
diagnosticAbi reference against the same shared report-diagnostic ABI identity
used by emitted reports, rather than leaving it unchecked. Reuse the existing
diagnostic ABI resource/identity symbols and add a verifier contract test
covering a profile/report ABI mismatch, ensuring packaged admission rejects
inconsistent bindings.

In `@crates/echo-edict-provider-verifier/tests/verifier_contract.rs`:
- Around line 918-936: Update the deep-recursion test to submit the valid
72-level field chain in deep_child as the verified core result, rather than
wrapping it in malicious_outer with an unknown discriminator. Preserve the
existing refusal assertions, but assert the depth-limit diagnostic produced
after traversing the chain so the recursion bound is exercised.
- Around line 744-765: The string-bound coverage only tests acceptance at the
limit and must also verify rejection above it. Add a test case in string bound
validation using 17 Unicode scalar values, run it through verify, and assert the
expected typed refusal rather than acceptance, reusing the existing setup and
assertion helpers.
- Around line 331-375: The verifier report contract in assert_report_common must
require canonical references for the verified Core, target profile, and semantic
closure, either directly in the report or through a mandatory attestation
envelope, including the required causal-basis/site and witnessed-hologram
bindings. Update the corresponding report construction and assertions while
preserving existing fields. In crates/echo-edict-provider-verifier/README.md
lines 42-46, document these bindings as part of the shipped contract rather than
deferring them to a future package.

In `@det-policy.yaml`:
- Around line 50-53: The echo-edict-provider-lowerer ownership path overlaps the
verifier component claim through its broad schema wildcard. Update the lowerer
entry’s paths to target only
schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm, while
preserving its existing ownership for the lowerer source and tests.

In `@xtask/src/main.rs`:
- Around line 544-549: Update require_checked_identity for Self::Verifier to
retain the verifier component returned by require_verifier_checked_identity(),
compare component.sha256_hex() against the approved checked-verifier SHA-256,
and return an error on mismatch before allowing promotion; ensure the Check flow
uses this validation rather than only comparing rebuilt bytes with --output, and
add a test covering a stale or malformed
APPROVED_CHECKED_VERIFIER_COMPONENT_SHA256.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7f11fb82-42b6-410a-80a4-5ab8515a6c9d

📥 Commits

Reviewing files that changed from the base of the PR and between 9264258 and 4bd4b5d.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm is excluded by !**/*.wasm
📒 Files selected for processing (42)
  • .github/workflows/ci.yml
  • .github/workflows/det-gates.yml
  • CHANGELOG.md
  • Cargo.toml
  • crates/echo-edict-provider-verifier/Cargo.toml
  • crates/echo-edict-provider-verifier/README.md
  • crates/echo-edict-provider-verifier/resources/authority-facts.echo-dpo.cbor
  • crates/echo-edict-provider-verifier/resources/authority-facts.echo-lawpack.cbor
  • crates/echo-edict-provider-verifier/resources/generated-artifact-profile.echo-dpo-registration.cbor
  • crates/echo-edict-provider-verifier/resources/lawpack.echo-dpo.cbor
  • crates/echo-edict-provider-verifier/resources/resource.lawpack-exports.cbor
  • crates/echo-edict-provider-verifier/resources/resource.lawpack-target-adapter.cbor
  • crates/echo-edict-provider-verifier/resources/resource.lawpack-verifier.cbor
  • crates/echo-edict-provider-verifier/resources/resource.target-cost-algebra.cbor
  • crates/echo-edict-provider-verifier/resources/resource.target-footprint-algebra.cbor
  • crates/echo-edict-provider-verifier/resources/resource.target-intrinsics.cbor
  • crates/echo-edict-provider-verifier/resources/resource.target-ir.cbor
  • crates/echo-edict-provider-verifier/resources/resource.target-obstruction-taxonomy.cbor
  • crates/echo-edict-provider-verifier/resources/resource.target-operation-profiles.cbor
  • crates/echo-edict-provider-verifier/resources/resource.target-verifier-contract.cbor
  • crates/echo-edict-provider-verifier/resources/target-profile.echo-dpo.cbor
  • crates/echo-edict-provider-verifier/src/component.rs
  • crates/echo-edict-provider-verifier/src/lib.rs
  • crates/echo-edict-provider-verifier/src/semantic_resources.rs
  • crates/echo-edict-provider-verifier/tests/fixtures/edict-core.hex
  • crates/echo-edict-provider-verifier/tests/fixtures/edict-target-ir.hex
  • crates/echo-edict-provider-verifier/tests/verifier_contract.rs
  • crates/echo-edict-provider-verifier/wit/edict-target-provider.wit
  • det-policy.yaml
  • docs/architecture/application-contract-hosting.md
  • schemas/edict-provider/README.md
  • schemas/edict-provider/components/v1/README.md
  • scripts/ban-globals.sh
  • scripts/ban-nondeterminism.sh
  • scripts/tests/classify_changes.test.cjs
  • scripts/verify-edict-provider-host-v1.sh
  • scripts/verify-local.sh
  • tests/edict-provider-host-v1/tests/host_contract.rs
  • tests/edict-provider-host-v1/tests/verifier_resource_sync.rs
  • tests/hooks/test_verify_local.sh
  • xtask/src/main.rs
  • xtask/src/provider_lowerer_component.rs

Comment thread .github/workflows/ci.yml
Comment on lines +216 to +218
- uses: actions/checkout@v4
with:
submodules: false

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Disable credential persistence for workflow security.

The actions/checkout step persists the GitHub token in the local Git configuration by default. Explicitly disable this to limit credential exposure during subsequent run steps.

🛡️ Proposed fix
             - uses: actions/checkout@v4
               with:
                   submodules: false
+                  persist-credentials: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- uses: actions/checkout@v4
with:
submodules: false
- uses: actions/checkout@v4
with:
submodules: false
persist-credentials: false
🧰 Tools
🪛 zizmor (1.26.1)

[warning] 216-218: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 216-216: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 216 - 218, Update the
actions/checkout@v4 step to explicitly disable credential persistence by setting
persist-credentials to false in its with configuration, while preserving the
existing submodules setting.

Source: Linters/SAST tools

Comment on lines +689 to +713
|| !array_field(value, "requirements")
.is_some_and(|requirements| requirements.iter().all(validate_requirement_shape))
|| !array_field(value, "steps").is_some_and(|steps| steps.iter().all(validate_step_shape))
{
return false;
}
map_field(value, "result").is_some_and(validate_target_expr_shape)
}

fn validate_budget_shape(value: &CanonicalValueV1) -> bool {
has_exact_fields(
value,
&["maxSteps", "maxAllocatedBytes", "maxOutputBytes"],
) && ["maxSteps", "maxAllocatedBytes", "maxOutputBytes"]
.into_iter()
.all(|field| {
matches!(map_field(value, field), Some(CanonicalValueV1::Integer(value)) if *value >= 0)
})
}

fn validate_requirement_shape(value: &CanonicalValueV1) -> bool {
has_exact_fields(value, &["id", "predicate", "onFailure"])
&& text_field(value, "id").is_some_and(|id| !id.is_empty())
&& map_field(value, "predicate").and_then(as_map).is_some()
&& map_field(value, "onFailure").and_then(as_map).is_some()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Separate structural validity from unsupported Target IR semantics.

Err(Unsupported) is treated as a valid expression shape, but preflight_expr does not validate any fields for variant, match, list, map, or if; requirement predicates and failure handlers likewise accept arbitrary maps. Consequently, malformed Target IR such as {"kind":"if"} reaches relation_failure and returns a successful rejected report instead of InvalidSemanticArtifact. Fully validate known shapes and depth before classifying semantic support.

Also applies to: 753-757

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/echo-edict-provider-verifier/src/lib.rs` around lines 689 - 713,
Update preflight_expr and validate_target_expr_shape to fully validate the
structure and nesting depth of known Target IR variants, including variant,
match, list, map, and if, before classifying unsupported semantics as
Err(Unsupported). Reuse the same validation for requirement predicates and
onFailure handlers instead of accepting arbitrary maps, so malformed expressions
such as an if without required fields return InvalidSemanticArtifact rather than
a successful rejected report.

Comment on lines +178 to +247
fn validate_references(&self) -> Result<(), SemanticResourceError> {
assert_ref(
field(&self.profile, "targetIr", "target-profile.targetIr")?,
TARGET_IR,
&self.target_ir,
"target-profile.targetIr",
)?;
assert_ref(
field(&self.profile, "intrinsics", "target-profile.intrinsics")?,
INTRINSICS,
&self.intrinsics,
"target-profile.intrinsics",
)?;
assert_ref(
field(
&self.profile,
"footprintAlgebra",
"target-profile.footprintAlgebra",
)?,
FOOTPRINT,
&self.footprint,
"target-profile.footprintAlgebra",
)?;
assert_ref(
field(&self.profile, "costAlgebra", "target-profile.costAlgebra")?,
COST,
&self.cost,
"target-profile.costAlgebra",
)?;
assert_ref(
field(
&self.profile,
"obstructionTaxonomy",
"target-profile.obstructionTaxonomy",
)?,
OBSTRUCTIONS,
&self.obstructions,
"target-profile.obstructionTaxonomy",
)?;
assert_ref(
field(
&self.profile,
"operationProfiles",
"target-profile.operationProfiles",
)?,
OPERATION_PROFILES,
&self.operation_profiles,
"target-profile.operationProfiles",
)?;
assert_ref(
field(&self.profile, "verifier", "target-profile.verifier")?,
VERIFIER,
&self.verifier,
"target-profile.verifier",
)?;
let generated = exact_array(
field(
&self.profile,
"generatedArtifactProfiles",
"target-profile.generatedArtifactProfiles",
)?,
1,
"target-profile.generatedArtifactProfiles",
)?;
assert_ref(
&generated[0],
GENERATED_PROFILE,
&self.generated_profile,
"target-profile.generatedArtifactProfiles[0]",
)?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Bind the report diagnostic ABI through the profile crossing.

The profile's diagnosticAbi reference is skipped here, while crates/echo-edict-provider-verifier/tests/verifier_contract.rs, Lines 358-370 independently hard-code the report ABI. A resource update could therefore leave the profile and emitted report bound to different diagnostic schemas while packaged admission still succeeds. Validate both through one shared identity and add a mismatch test.

The PR objective requires exact semantic-resource and artifact identity binding.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/echo-edict-provider-verifier/src/semantic_resources.rs` around lines
178 - 247, Update validate_references to validate the profile’s diagnosticAbi
reference against the same shared report-diagnostic ABI identity used by emitted
reports, rather than leaving it unchecked. Reuse the existing diagnostic ABI
resource/identity symbols and add a verifier contract test covering a
profile/report ABI mismatch, ensuring packaged admission rejects inconsistent
bindings.

Comment on lines +331 to +375
fn assert_report_common(
report: &CanonicalValueV1,
target_ir_reference: &ResourceRef,
expected_outcome: &str,
) {
let CanonicalValueV1::Map(fields) = report else {
panic!("report is not a map");
};
assert_eq!(fields.len(), 5);
assert_eq!(
text_value(map_field(report, "apiVersion")),
"echo.verifier-report/v1"
);
assert_eq!(
map_field(report, "targetIr"),
&map([
("id", text(&target_ir_reference.coordinate)),
(
"digest",
CanonicalValueV1::Array(vec![
text("sha256"),
CanonicalValueV1::Bytes(target_ir_reference.digest.bytes.clone()),
]),
),
])
);
assert_eq!(text_value(map_field(report, "outcome")), expected_outcome);
let diagnostic_abi = map_field(report, "diagnosticAbi");
assert_eq!(
text_value(map_field(diagnostic_abi, "id")),
"edict.diagnostics/v1"
);
assert_eq!(
map_field(diagnostic_abi, "digest"),
&CanonicalValueV1::Array(vec![
text("sha256"),
CanonicalValueV1::Bytes(
hex::decode(DIAGNOSTIC_ABI_DIGEST).expect("diagnostic digest is valid")
),
])
);
assert_eq!(
map_field(report, "diagnosticBytes"),
&CanonicalValueV1::Bytes(Vec::new())
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Bind the verifier report to its complete causal basis.

The executable contract and documentation both define a report that identifies Target IR but not the exact Core, target profile, or semantic closure used to reach the decision.

  • crates/echo-edict-provider-verifier/tests/verifier_contract.rs#L331-L375: require canonical references for the verified Core, target profile, and semantic closure in the report or mandatory attestation envelope.
  • crates/echo-edict-provider-verifier/README.md#L42-L46: document those bindings as part of this shipped contract instead of deferring them to a future package.

As per coding guidelines, public Echo surfaces require an explicit causal basis/site and witnessed hologram.

📍 Affects 2 files
  • crates/echo-edict-provider-verifier/tests/verifier_contract.rs#L331-L375 (this comment)
  • crates/echo-edict-provider-verifier/README.md#L42-L46
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/echo-edict-provider-verifier/tests/verifier_contract.rs` around lines
331 - 375, The verifier report contract in assert_report_common must require
canonical references for the verified Core, target profile, and semantic
closure, either directly in the report or through a mandatory attestation
envelope, including the required causal-basis/site and witnessed-hologram
bindings. Update the corresponding report construction and assertions while
preserving existing fields. In crates/echo-edict-provider-verifier/README.md
lines 42-46, document these bindings as part of the shipped contract rather than
deferring them to a future package.

Source: Coding guidelines

Comment on lines +744 to +765
#[test]
fn string_bound_counts_unicode_scalar_values() {
let authored = "🦀".repeat(16);
let bounded_input = map([
("kind", text("const")),
(
"value",
map([("kind", text("string")), ("value", text(&authored))]),
),
]);
let mut core = core_value();
*map_field_mut(core_effect_mut(&mut core), "input") = bounded_input.clone();
let mut target_ir = target_ir_value();
*map_field_mut(target_step_mut(&mut target_ir), "input") = bounded_input;
let mut case = request();
bind_core(&mut case, &core);
bind_target_ir(&mut case, &target_ir);
let target_ir_reference = case.target_ir.reference.clone();

let success = verify(case).expect("sixteen Unicode scalar values remain within the bound");
assert_accepted(&success, &target_ir_reference);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Test rejection above the Unicode scalar limit.

Accepting 16 non-ASCII scalars proves byte length is not used, but an implementation that omits the upper bound entirely also passes. Add a 17-scalar case and assert the required typed refusal.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/echo-edict-provider-verifier/tests/verifier_contract.rs` around lines
744 - 765, The string-bound coverage only tests acceptance at the limit and must
also verify rejection above it. Add a test case in string bound validation using
17 Unicode scalar values, run it through verify, and assert the expected typed
refusal rather than acceptance, reusing the existing setup and assertion
helpers.

Comment on lines +918 to +936
let mut deep_child = map([("kind", text("unknown"))]);
for _ in 0..72 {
deep_child = map([
("kind", text("field")),
("base", deep_child),
("field", text("x")),
]);
}
let malicious_outer = map([("kind", text("unknown")), ("base", deep_child)]);
let mut malicious_core = core_value();
*core_result_mut(&mut malicious_core) = malicious_outer;
let mut request = request();
bind_core(&mut request, &malicious_core);
let refusal = verify(request).expect_err("the outer discriminator must fail closed");
assert_eq!(refusal.kind, ProviderRefusalKind::InvalidSemanticArtifact);
assert_eq!(
refusal.diagnostics[0].code,
"echo.verifier.invalid-expression-discriminator"
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Exercise the recursion bound instead of short-circuiting at the root.

malicious_outer has an unknown discriminator, so verification rejects before traversing its 72-level base. Submit the valid field chain itself and assert the depth-limit refusal; otherwise this test cannot detect unbounded recursion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/echo-edict-provider-verifier/tests/verifier_contract.rs` around lines
918 - 936, Update the deep-recursion test to submit the valid 72-level field
chain in deep_child as the verified core result, rather than wrapping it in
malicious_outer with an unknown discriminator. Preserve the existing refusal
assertions, but assert the depth-limit diagnostic produced after traversing the
chain so the recursion bound is exercised.

Comment thread det-policy.yaml
Comment on lines +50 to +53
echo-edict-provider-verifier:
class: DET_CRITICAL
owner_role: "Tooling Engineer"
paths: ["crates/echo-edict-provider-verifier/**", "schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm", "tests/edict-provider-host-v1/**"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Tighten path globs to prevent overlapping ownership.

This entry explicitly claims schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm. However, the echo-edict-provider-lowerer entry at line 49 already claims the broad schemas/edict-provider/components/v1/** glob, which inadvertently includes this new verifier component. Consider updating the lowerer's path to explicitly target lowerer.echo-dpo.component.wasm instead of using a blanket wildcard to maintain strict, non-overlapping ownership boundaries.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@det-policy.yaml` around lines 50 - 53, The echo-edict-provider-lowerer
ownership path overlaps the verifier component claim through its broad schema
wildcard. Update the lowerer entry’s paths to target only
schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm, while
preserving its existing ownership for the lowerer source and tests.

Comment thread xtask/src/main.rs
Comment on lines +544 to +549
fn require_checked_identity(self) -> provider_lowerer_component::Result<()> {
match self {
Self::Lowerer => Ok(()),
Self::Verifier => {
provider_lowerer_component::require_verifier_checked_identity().map(|_| ())
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Bind check to the approved SHA-256, not just the checked file.

require_checked_identity() discards the verifier digest, while Check only compares rebuilt bytes with --output. A source plus checked-WASM change can therefore pass with a stale or malformed APPROVED_CHECKED_VERIFIER_COMPONENT_SHA256, bypassing the promotion identity gate. Compare component.sha256_hex() with the approved digest and add a mismatch test.

Also applies to: 655-664

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@xtask/src/main.rs` around lines 544 - 549, Update require_checked_identity
for Self::Verifier to retain the verifier component returned by
require_verifier_checked_identity(), compare component.sha256_hex() against the
approved checked-verifier SHA-256, and return an error on mismatch before
allowing promotion; ensure the Check flow uses this validation rather than only
comparing rebuilt bytes with --output, and add a test covering a stale or
malformed APPROVED_CHECKED_VERIFIER_COMPONENT_SHA256.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement the Echo Target IR semantic verifier component

1 participant