Skip to content

Build verified external applications through provider components - #170

Merged
flyingrobots merged 26 commits into
mainfrom
task/169-compile-standalone-hello-echo
Jul 28, 2026
Merged

Build verified external applications through provider components#170
flyingrobots merged 26 commits into
mainfrom
task/169-compile-standalone-hello-echo

Conversation

@flyingrobots

@flyingrobots flyingrobots commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Compile standalone applications from exact Edict source and a validated lawpack, adapter, target, and provider closure. Invoke the checked provider lowerer and structurally separate verifier, then publish the accepted package and report as one staged pair.

Validation:

  • cargo xtask verify
  • external Hello Echo build package: 8a602e9bf2dfeae1a3bc033d299dc7b6b348a08c777756c7b1b855bd099dab93
  • external Hello Echo verification report: 8a72bff53649a448d7f880ed27bb21a52daab3a43eb2e0579e46ac35296e34dd

This compiles and verifies artifacts. It does not execute them or define an application runtime lifecycle.

Closes #169.

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Copy link
Copy Markdown
Owner Author

@codex please review

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@flyingrobots, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 7 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 81a02429-9e7f-47a4-b3c8-f3fa1e4d7b70

📥 Commits

Reviewing files that changed from the base of the PR and between 2e3f52f and 0595abf.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • crates/edict-cli/src/application_build.rs
  • crates/edict-cli/src/main.rs
  • crates/edict-cli/tests/jsonl_cli.rs
  • crates/edict-syntax/src/target_ir.rs
  • crates/edict-syntax/tests/provider.rs
  • crates/edict-syntax/tests/target_ir.rs
  • docs/topics/cli/test-plan.md
  • xtask/src/tests.rs

Walkthrough

The PR adds canonical lawpack and direct-adapter loaders, standalone build CLI execution, provider lowerer/verifier integration, recursive required-key dispatch, canonical fixtures, golden generation, and corresponding ABI documentation and tests.

Changes

Lawpack build pipeline

Layer / File(s) Summary
Lawpack bundle and adapter validation
crates/edict-syntax/src/lawpack.rs, crates/edict-syntax/src/lawpack_adapter.rs
Canonical manifests, exports, dependencies, adapters, digests, closure obligations, and compiler/Target IR facts are decoded and validated.
Application build orchestration
crates/edict-cli/src/application_build.rs
Application configuration is validated, source and lawpacks are compiled, providers are invoked, accepted reports are required, and outputs are atomically written.
CLI build operation
crates/edict-cli/src/main.rs, docs/schemas/edict.compiler-settings.v1.schema.json
JSONL requests support build with settings, application validation, build dispatch, and terminal status output.
Provider schema and closure handling
crates/edict-provider-schema/*, crates/edict-syntax/src/contract_bundle.rs
The lawpack-adapter contract is assembled, required-key recursive dispatch is supported, and provider-supplied semantic closures are corroborated.
Golden artifacts and fixtures
xtask/src/lawpack_goldens.rs, fixtures/lawpack/*
Hello Echo and causal-cell manifests, adapters, configurations, source, Core, Target IR, and digest sidecars are generated and checked.
Contracts, tests, and documentation
docs/*, crates/edict-syntax/tests/*, xtask/src/tests.rs
ABI rules, requirements, test plans, recursive dispatch coverage, loader cases, adapter conformance, and build behavior are documented and tested.

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

Possibly related issues

Possibly related PRs

Poem

Lawpacks bloom in canonical bytes,
Adapters bind their guarded gates.
Core descends through Echo’s light,
Providers judge the package right.
Goldens watch each digest gleam.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.35% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: building verified external applications via provider components.
Description check ✅ Passed The description matches the changeset and accurately describes the new build flow, validation, and staged artifact publication.

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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 49173d80bc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/edict-cli/src/application_build.rs Outdated
Comment thread crates/edict-cli/src/application_build.rs Outdated
Comment thread crates/edict-cli/src/application_build.rs Outdated
Comment thread docs/topics/cli/test-plan.md Outdated
Comment thread crates/edict-cli/src/application_build.rs Outdated
Comment thread crates/edict-syntax/src/lawpack.rs
Comment thread crates/edict-cli/src/application_build.rs Outdated
Comment thread crates/edict-cli/src/application_build.rs
Comment thread crates/edict-cli/src/main.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 25

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
crates/edict-provider-schema/src/recursive_dispatch.rs (1)

666-704: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate-occurrence detection is copy-pasted between the tagged and required-key branches.

specialize_choice's tagged_choice branch (Lines 676-684) and the new required_key_choice branch (Lines 692-698) both implement "find at most one map entry whose key matches a target text, else reject" with slightly different filter/collect idioms. Worth extracting a small shared helper (e.g. fn single_matching_entry<'a>(entries: &'a [(CanonicalValue, CanonicalValue)], key: &str) -> Result<Option<&'a CanonicalValue>, ()>) to keep this fail-closed invariant defined once.

🤖 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/edict-provider-schema/src/recursive_dispatch.rs` around lines 666 -
704, Extract the duplicated map-entry occurrence logic from specialize_choice
into a shared helper such as single_matching_entry, returning the sole matching
value, None when absent, and an error for duplicates. Use it in both the
tagged_choice and required_key_choice branches, preserving their existing
fail-closed behavior and discriminator/type handling.
docs/schemas/edict.compiler-settings.v1.schema.json (1)

189-218: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Every if clause here is missing required, so all three fire simultaneously on a document that omits operation.

{"properties": {"operation": {"const": "build"}}} succeeds vacuously when operation is absent — properties imposes nothing on properties that are not present. The check, project, and build conditions therefore all evaluate true for an operation-less document, and all three then blocks apply at once: type must simultaneously be "compilerSettings" and "settings", application must be both absent and required. The document is already invalid via the top-level required at Line 8, so nothing is let through — but callers get a pile of contradictory sub-errors instead of "missing operation", and the moment operation gains a default this becomes a live bug.

This is the canonical JSON Schema if/then footgun. Add "required": ["operation"] to all three conditions, including the pre-existing check clause at Lines 174-178.

🐛 Proposed fix (apply the same shape to all three branches)
     {
       "if": {
+        "required": ["operation"],
         "properties": {
           "operation": { "const": "build" }
         }
       },
🤖 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 `@docs/schemas/edict.compiler-settings.v1.schema.json` around lines 189 - 218,
Add "required": ["operation"] to the condition schemas of all three operation
branches, including the existing check branch and the project/build branches
identified by their operation const values. Keep each branch’s then constraints
unchanged so they only apply when operation is explicitly present.
crates/edict-cli/src/main.rs (2)

507-520: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

The check branch now rejects application while telling the user it is a "project-only" setting.

You added settings.application.is_some() to the guard at Line 508 but left the message at Line 517 untouched. A caller who sends operation: "check" with an application path is now told:

emit, compilerContext, and target are project-only settings

— which names three fields they did not send, omits the one they did, and misclassifies a build-only field as project-only. You got this exactly right for the Project branch at Lines 523-530 with its own dedicated "application" is a build-only setting" message. Do the same here instead of smuggling a fourth condition into a three-field message.

🐛 Proposed fix: split the application check out of the shared message
         Operation::Check => {
-            if settings.application.is_some()
-                || !settings.emit.is_empty()
+            if settings.application.is_some() {
+                return Err(CliFailure {
+                    command: COMMAND_CHECK,
+                    kind: "InvalidSettings",
+                    line: Some(line),
+                    message: "`application` is a build-only setting".to_owned(),
+                });
+            }
+            if !settings.emit.is_empty()
                 || settings.compiler_context.is_some()
                 || settings.target.is_some()
             {
🤖 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/edict-cli/src/main.rs` around lines 507 - 520, Update the
Operation::Check validation to handle settings.application separately from the
existing emit, compiler_context, and target validation, using a dedicated
message that identifies application as a build-only setting. Keep the shared
project-only message limited to emit, compilerContext, and target.

378-385: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

A build request carrying compiler-input records is accepted, then the inputs are thrown away in silence.

Line 378 was relaxed to skip the MissingInput error for Build, but nothing was added to reject a build request that supplies input records. run_request then short-circuits at Line 714 into run_build_request(&request.settings), which never touches request.inputs. The caller gets exit 0 and an ok status while every edict.compiler.input/v1 record they sent was parsed, validated, and discarded.

docs/topics/cli/README.md Line 26 states the contract flatly: "A build request contains one settings record and no compiler-input records." Silently ignoring input on a fail-closed compiler boundary is the wrong reading of that sentence. Reject it.

🐛 Proposed fix: fail closed on unexpected build inputs
-    if inputs.is_empty() && settings.operation != Operation::Build {
+    if settings.operation == Operation::Build {
+        if !inputs.is_empty() {
+            return Err(CliFailure {
+                command: COMMAND_BUILD,
+                kind: "InvalidRecord",
+                line: None,
+                message: "build requests must not contain compiler input records".to_owned(),
+            });
+        }
+    } else if inputs.is_empty() {
         return Err(CliFailure {
             command: command_for_operation(settings.operation),
             kind: "MissingInput",
             line: None,
             message: "request must contain at least one compiler input record".to_owned(),
         });
     }

Also applies to: 714-716

🤖 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/edict-cli/src/main.rs` around lines 378 - 385, Update the request
validation in run_request around the existing inputs.is_empty() check and the
build short-circuit to reject any Build request with compiler-input records,
using the established CliFailure/MissingInput error pattern or an appropriate
validation error. Preserve the current requirement for non-Build operations to
include at least one input, and ensure invalid Build requests do not reach
run_build_request with inputs silently discarded.
xtask/src/tests.rs (1)

2020-2043: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert the exact compiler-settings schema contract.

json_string_array_contains permits unsupported extra enum values, while properties.contains_key("application") accepts an arbitrary or incomplete property definition. This test can pass after the public build contract is widened or the application schema loses required validation. Compare the exact allowed enum values and validate the application property's type and required fields.

🤖 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/tests.rs` around lines 2020 - 2043, Update the compiler-settings
schema assertions around record_type, operation, and application to enforce the
exact public contract: compare enum arrays against the complete expected values
rather than using json_string_array_contains, and inspect application to require
the expected object type and all required validation fields. Keep the existing
missing-property diagnostics while rejecting unsupported enum values and
incomplete application definitions.
🤖 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 `@crates/edict-cli/Cargo.toml`:
- Around line 19-25: Remove the direct sha2 dependency from the CLI and update
application_build.rs::provider_digest to reuse an exported digest-framing helper
from edict-syntax, preserving the canonical [CORE_DIGEST_FRAME, domain, value]
behavior. Expose the existing digest_value logic in edict-syntax rather than
duplicating the hash implementation, and use the workspace’s standard dependency
version convention instead of pinning a patch release.

In `@crates/edict-cli/src/application_build.rs`:
- Around line 748-754: The adapter identity must match the profile-selected
descriptor and must not index the optional adapter list. Expose the selected
descriptor’s adapter ID on ValidatedLawpackAdapter, then use it in both
01-lawpack-adapter semantic_input calls at
crates/edict-cli/src/application_build.rs lines 748-754 and 806-812, replacing
the target_adapters[0] lookup.
- Around line 100-102: Replace the unchecked indexing of config.sources and
loaded_lawpacks in the application build flow with local, total access that
handles missing entries without panicking. Preserve the existing successful-path
behavior for the first source and lawpack, and return the established structured
error result when either collection is empty; update the code near resolve and
the loaded_lawpacks use rather than relying on validate_application_manifest.
- Around line 516-539: Remove the duplicated effect projection and single-target
validation from validate_target_configuration_binding and single_configuration
by introducing or reusing one shared accessor for the sole target configuration.
Have both paths obtain the configuration through that accessor, while keeping
the existing InvalidLawpackAdapter failure and preserving
validate_target_configuration_binding’s digest check against the exact bytes
used by the provider.
- Around line 1032-1069: Update the output publication function around the
package/report staging and renames to use process-unique temporary filenames,
fsync both staged files before publication, and clean up all temporary files on
every failure path. Publish the verification report before the executable
package so the package is the final visible artifact, and preserve the existing
failure type/messages and successful output paths; if pair-atomicity is required
by the surrounding contract, stage both files in a temporary directory and
rename that directory once.
- Around line 541-555: Refactor invoke_lowerer and invoke_verifier to accept one
borrowed context struct containing coordinate, core_bytes, target_profile,
loaded, adapter, source_bytes, and target_ir_bytes, then update their call sites
and field accesses while preserving behavior. Replace the bare
#[allow(clippy::too_many_arguments)] on both functions with the file’s existing
reason = "…" suppression style, or remove it if the refactor eliminates the
warning.
- Around line 346-381: Update validate_application_manifest and its callers to
enforce root confinement for every resolved application path, using the
manifest’s parent directory as the root. Reject absolute paths and paths
escaping via .. for sources, lawpacks, target.providerPackage, and
outputDirectory before build performs any reads or writes; preserve existing
validation errors for unrelated manifest fields.
- Around line 618-626: Update the diagnostic handling around
response.diagnostics so only ProviderDiagnosticSeverity values that are
designated build-blocking return failure. Preserve non-blocking warning/info
diagnostics without failing the build, and ensure failure_kind strings such as
ProviderLowererFailed are used only for blocking severities; align this logic
with the advertised max_diagnostic_count behavior.
- Around line 1072-1094: Align response_limits() and host_limits() so the
requested response envelope matches the enforced host envelope. Either enforce
the 64 KiB response_limits().max_total_response_bytes value in
preflight_limits(), or, if 3 MiB is the intended limit, update
host_limits().max_output_bytes accordingly; ensure the two limits cannot drift.
- Around line 487-514: Validate provider roles in check_artifacts before
read_provider_artifact constructs paths, rejecting empty or unsafe values
containing path separators, traversal segments, or absolute/drive-path syntax.
Preserve the existing uniqueness checks and ensure invalid roles produce the
established manifest-validation failure rather than reaching filesystem reads.
- Around line 1011-1023: Replace the any-based acceptance check in the provider
verification gate with a single lookup of the “outcome” key, then require that
sole binding to equal “accepted”; preserve the existing
ProviderVerificationRejected error for missing, non-text, or non-accepted
outcomes.

In `@crates/edict-cli/src/main.rs`:
- Around line 734-753: Replace the hard-coded processed-input count in
run_build_request’s status_record call with a meaningful build-specific value,
preferably derived from the application manifest’s source count. If that value
cannot be obtained there, document the build count semantics in the CLI
documentation so the published status field is unambiguous and comparable across
commands.
- Around line 415-427: Use the single "compilerSettings" record type for all
operations, including Build, by removing the Operation::Build-specific
expected_record_type branch and validating settings.record_type against that
constant. Update the corresponding published schema and documentation references
so the contract no longer permits "settings" for build.
- Around line 482-506: Update the Operation::Build validation to reject
non-default directory_extensions values, matching the stated build contract, and
ensure run_build_request does not accept or silently ignore custom directory
extensions. Consolidate the duplicate application-required validation so one
owner validates and returns the application path, removing the unreachable
re-validation in the later build flow.

In `@crates/edict-cli/tests/jsonl_cli.rs`:
- Around line 57-82: The test
build_accepts_application_request_without_compiler_input_records only proves
manifest-read failure, so add executable Hello Echo end-to-end cases covering
successful outputs and fail-closed provider refusal, non-accepted verification,
and diagnostics, or downgrade and split CLI-REQ-015 accordingly. Also create the
missing application path under a TempDir instead of relying on the bare relative
path "missing-edict-application.json".

In `@crates/edict-syntax/src/contract_bundle.rs`:
- Around line 575-603: Document the trust boundary in the (None, Some(actual))
arm that derives expected_lawpacks from actual.lawpacks: explain that this is
safe only because the later supplied_lawpacks check corroborates the closure,
and state that callers must populate lawpacks from a source independent of the
provider-asserted Target IR closure. Keep the existing source_core validation
and closure comparison behavior unchanged.

In `@crates/edict-syntax/src/lawpack_adapter.rs`:
- Around line 706-723: Remove the local DIGEST_FRAME and digest_value
implementation in crates/edict-syntax/src/lawpack_adapter.rs:706-723, replacing
its callers with crate::canonical::digest_canonical_value as used by lawpack.rs.
Remove the duplicated review-string implementation at
crates/edict-syntax/src/lawpack_adapter.rs:877-885, add or reuse a shared
sha256_review_string in the canonical module, and update both this site and
lawpack.rs:1921-1930 to call it.
- Around line 231-240: Update the obstruction coordinate collection in the
adapter effects loop to gather mapped target obstruction names from each failure
mapping’s values, rather than extending with the lawpack failure-ident keys.
Preserve the existing local effect and TargetEffectLowering construction, and
populate TargetIrLoweringFacts.obstruction_coordinates with the declared target
coordinates used for obstruction-arm validation.

In `@crates/edict-syntax/src/lawpack.rs`:
- Around line 759-791: Update parse_array_field to accept a coordinate projector
for the parsed T value and use it for duplicate detection after parse returns,
removing the second traversal through export_coordinate and the raw
CanonicalValue. Update each caller to provide the appropriate coordinate
accessor for its parsed item type, preserving required nonempty coordinate
validation and DuplicateIdentity behavior.

In `@crates/edict-syntax/tests/lawpack.rs`:
- Around line 198-221: Extract the repeated decode–mutate–re-encode–validate
setup from lawpack_adapter_requires_a_typed_target_configuration_reference,
lawpack_adapter_requires_complete_exported_effect_coverage, and
lawpack_adapter_corroborates_footprint_cost_and_failure_obligations into a
shared test helper. Have the helper accept a mutation closure and expected
LawpackAdapterFailureKind, preserve the existing digest rebinding order, bundle
construction, canonical encoding, decode_lawpack_adapter call, and single-kind
assertion, then replace each test’s duplicated choreography with the helper
invocation.

In `@docs/abi/edict-lawpack-adapter.cddl`:
- Around line 46-47: Align the write-class vocabulary across all affected sites:
in docs/abi/edict-lawpack-adapter.cddl lines 46-47, replace "modify" with
"replace" and add "custom"; in crates/edict-syntax/src/lawpack_adapter.rs lines
639-655, preserve the existing accepted set and thread the effect coordinate
into the InvalidWriteClass failure path instead of using the hardcoded constant;
in fixtures/provider-contracts/v1/edict-provider-contracts.cddl lines 585-586,
make no direct edit and regenerate the fixture with the provider-contract-pack
xtask after updating the upstream schema.

In `@docs/topics/cli/README.md`:
- Around line 24-44: Expand the build-request documentation around the
implemented operations to state that its settings record uses type "settings",
not "compilerSettings", and add a concrete valid edict.application/v1 manifest
example covering coordinate, sources, lawpacks, target, and outputDirectory.
Document that outputDirectory is resolved relative to the manifest’s parent and
contains the two emitted artifacts, or alternatively add the authoritative JSON
Schema under docs/schemas and link it from the Stream Contract Artifacts table.

In `@docs/topics/cli/test-plan.md`:
- Line 99: Update the Fixtures table in test-plan.md to add entries for the
standalone Hello Echo lawpack corpus under fixtures/lawpack/hello-echo/,
covering its manifest, exports, adapter, target-IR, configuration, and .sha256
sidecars. Name cargo xtask lawpack-goldens --check as the oracle, matching the
existing CLI golden-check row style, and ensure CLI-TP-027 references the
documented fixture entry so requirements, case IDs, fixtures, and oracles remain
linked.

In `@docs/topics/lawpacks/test-plan.md`:
- Line 74: Update the TP-008 oracle and evidence entries to include the
InvalidWriteClass adapter failure mode, with a dedicated case ID, requirement
linkage, fixture, and executable oracle. Add or reference a negative test
covering the decoder/edict-lawpack-adapter.cddl write-class vocabulary mismatch,
and assert the stable LawpackAdapterFailureKind::InvalidWriteClass result rather
than only checking for a generic failure.

In `@xtask/src/lawpack_goldens.rs`:
- Around line 99-102: Update the digest_value call that computes
configuration_digest to use the declared CAUSAL_CELL_CONFIGURATION_COORDINATE
instead of the API-version string, while preserving the existing
configuration_value input and error propagation.

---

Outside diff comments:
In `@crates/edict-cli/src/main.rs`:
- Around line 507-520: Update the Operation::Check validation to handle
settings.application separately from the existing emit, compiler_context, and
target validation, using a dedicated message that identifies application as a
build-only setting. Keep the shared project-only message limited to emit,
compilerContext, and target.
- Around line 378-385: Update the request validation in run_request around the
existing inputs.is_empty() check and the build short-circuit to reject any Build
request with compiler-input records, using the established
CliFailure/MissingInput error pattern or an appropriate validation error.
Preserve the current requirement for non-Build operations to include at least
one input, and ensure invalid Build requests do not reach run_build_request with
inputs silently discarded.

In `@crates/edict-provider-schema/src/recursive_dispatch.rs`:
- Around line 666-704: Extract the duplicated map-entry occurrence logic from
specialize_choice into a shared helper such as single_matching_entry, returning
the sole matching value, None when absent, and an error for duplicates. Use it
in both the tagged_choice and required_key_choice branches, preserving their
existing fail-closed behavior and discriminator/type handling.

In `@docs/schemas/edict.compiler-settings.v1.schema.json`:
- Around line 189-218: Add "required": ["operation"] to the condition schemas of
all three operation branches, including the existing check branch and the
project/build branches identified by their operation const values. Keep each
branch’s then constraints unchanged so they only apply when operation is
explicitly present.

In `@xtask/src/tests.rs`:
- Around line 2020-2043: Update the compiler-settings schema assertions around
record_type, operation, and application to enforce the exact public contract:
compare enum arrays against the complete expected values rather than using
json_string_array_contains, and inspect application to require the expected
object type and all required validation fields. Keep the existing
missing-property diagnostics while rejecting unsupported enum values and
incomplete application definitions.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 000c492f-9b55-4e39-baa1-dc727174e497

📥 Commits

Reviewing files that changed from the base of the PR and between 337e014 and 49173d8.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (67)
  • CHANGELOG.md
  • crates/edict-cli/Cargo.toml
  • crates/edict-cli/src/application_build.rs
  • crates/edict-cli/src/main.rs
  • crates/edict-cli/tests/jsonl_cli.rs
  • crates/edict-provider-schema/src/contract_pack.rs
  • crates/edict-provider-schema/src/recursive_dispatch.rs
  • crates/edict-provider-schema/tests/provider_contract_pack.rs
  • crates/edict-provider-schema/tests/registry.rs
  • crates/edict-syntax/src/contract_bundle.rs
  • crates/edict-syntax/src/lawpack.rs
  • crates/edict-syntax/src/lawpack_adapter.rs
  • crates/edict-syntax/src/lib.rs
  • crates/edict-syntax/src/parser.rs
  • crates/edict-syntax/src/target_profile.rs
  • crates/edict-syntax/tests/contract_bundle.rs
  • crates/edict-syntax/tests/lawpack.rs
  • crates/edict-syntax/tests/target_profile.rs
  • docs/REQUIREMENTS.md
  • docs/SPEC_edict-lawpack-abi-v1.md
  • docs/SPEC_edict-target-profile-abi-v1.md
  • docs/abi/edict-lawpack-adapter.cddl
  • docs/abi/edict-target-profile.cddl
  • docs/schemas/edict.compiler-settings.v1.schema.json
  • docs/topics/cli/README.md
  • docs/topics/cli/test-plan.md
  • docs/topics/compiler-spine/test-plan.md
  • docs/topics/contract-bundles/README.md
  • docs/topics/contract-bundles/test-plan.md
  • docs/topics/fixtures/test-plan.md
  • docs/topics/lawpacks/README.md
  • docs/topics/lawpacks/test-plan.md
  • docs/topics/providers/test-plan.md
  • docs/topics/target-ir/test-plan.md
  • docs/topics/target-profiles/README.md
  • docs/topics/target-profiles/test-plan.md
  • fixtures/README.md
  • fixtures/lawpack/causal-cell/README.md
  • fixtures/lawpack/causal-cell/adapter.cbor
  • fixtures/lawpack/causal-cell/adapter.sha256
  • fixtures/lawpack/causal-cell/echo-operation-configuration.cbor
  • fixtures/lawpack/causal-cell/echo-operation-configuration.sha256
  • fixtures/lawpack/causal-cell/exports.cbor
  • fixtures/lawpack/causal-cell/exports.sha256
  • fixtures/lawpack/causal-cell/manifest.cbor
  • fixtures/lawpack/causal-cell/manifest.sha256
  • fixtures/lawpack/hello-echo/README.md
  • fixtures/lawpack/hello-echo/adapter.cbor
  • fixtures/lawpack/hello-echo/adapter.sha256
  • fixtures/lawpack/hello-echo/create-greeting.core.cbor
  • fixtures/lawpack/hello-echo/create-greeting.core.sha256
  • fixtures/lawpack/hello-echo/create-greeting.edict
  • fixtures/lawpack/hello-echo/create-greeting.target-ir.cbor
  • fixtures/lawpack/hello-echo/create-greeting.target-ir.sha256
  • fixtures/lawpack/hello-echo/echo-operation-configuration.cbor
  • fixtures/lawpack/hello-echo/echo-operation-configuration.sha256
  • fixtures/lawpack/hello-echo/exports.cbor
  • fixtures/lawpack/hello-echo/exports.sha256
  • fixtures/lawpack/hello-echo/manifest.cbor
  • fixtures/lawpack/hello-echo/manifest.sha256
  • fixtures/provider-contracts/v1/edict-provider-contracts.cddl
  • fixtures/provider-contracts/v1/manifest.json
  • fixtures/providers/components/inventory.json
  • xtask/src/lawpack_goldens.rs
  • xtask/src/main.rs
  • xtask/src/provider_contract_pack.rs
  • xtask/src/tests.rs
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: rust msrv 1.94.0 (fmt · clippy · test)
  • GitHub Check: supply-chain (cargo-deny)
  • GitHub Check: rust stable (fmt · clippy · test)
🧰 Additional context used
📓 Path-based instructions (2)
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

When creating or changing documentation, give each page one primary reader job; keep user-facing task help separate from contributor architecture and evidence maps; use concrete, valid examples and show expected results when the result matters; put exact public facts in reference material and validate or generate them from authoritative sources when practical; and update affected documentation in the same change as behavior, schema, release, workflow, or public-surface changes, or state docs-impact: none with a concise rationale.

Files:

  • docs/SPEC_edict-lawpack-abi-v1.md
  • docs/REQUIREMENTS.md
  • docs/topics/target-profiles/README.md
  • docs/topics/target-ir/test-plan.md
  • docs/topics/compiler-spine/test-plan.md
  • docs/topics/contract-bundles/README.md
  • docs/SPEC_edict-target-profile-abi-v1.md
  • docs/topics/target-profiles/test-plan.md
  • docs/topics/providers/test-plan.md
  • docs/topics/cli/README.md
  • docs/topics/lawpacks/README.md
  • docs/topics/cli/test-plan.md
  • docs/topics/lawpacks/test-plan.md
  • docs/topics/fixtures/test-plan.md
  • docs/topics/contract-bundles/test-plan.md
docs/topics/**/{README.md,test-plan.md,architecture.md,rationale.md}

📄 CodeRabbit inference engine (AGENTS.md)

docs/topics/**/{README.md,test-plan.md,architecture.md,rationale.md}: For every nontrivial behavior, contract, workflow, release, schema, validation, or public-surface change, identify the owning topic shelf before editing code; create one if none exists; update test-plan.md before or alongside tests with requirement IDs, case IDs, fixtures, and oracles; write executable evidence; update the topic README.md only after behavior exists; mark planned cases implemented only when executable evidence exists; and run cargo xtask verify before claiming the shelf is current.
Do not churn topic shelves for purely mechanical edits that do not change a contract; when a change intentionally does not update a topic shelf, state why in the pull request body or final report.
Topic README.md files must not describe intended behavior before it lands; test-plan.md may include planned cases and known gaps; policy rows are for human-review workflow contracts and must not be used to avoid writing behavior tests; tests must assert code behavior and stable contract artifacts, not prose; negative tests should assert stable error kinds or structured artifacts, not merely is_err() or diagnostic text; release, CI, and publication workflows count as behavior when they define a project contract; avoid ceremonial documentation and update shelves because the contract changed, not because a path changed.

Files:

  • docs/topics/target-profiles/README.md
  • docs/topics/target-ir/test-plan.md
  • docs/topics/compiler-spine/test-plan.md
  • docs/topics/contract-bundles/README.md
  • docs/topics/target-profiles/test-plan.md
  • docs/topics/providers/test-plan.md
  • docs/topics/cli/README.md
  • docs/topics/lawpacks/README.md
  • docs/topics/cli/test-plan.md
  • docs/topics/lawpacks/test-plan.md
  • docs/topics/fixtures/test-plan.md
  • docs/topics/contract-bundles/test-plan.md
🪛 LanguageTool
fixtures/lawpack/hello-echo/README.md

[style] ~9-~9: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...omain-framed identity. - exports.cbor is the canonical export surface. - `export...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~10-~10: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ical export surface. - exports.sha256 is its hello.echo.exports/v1 domain-fram...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~11-~11: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...omain-framed identity. - adapter.cbor is the canonical direct declarative Echo t...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~12-~12: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...Echo target adapter. - adapter.sha256 is its manifest-bound domain-framed identi...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~13-~13: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: .... - echo-operation-configuration.cbor is the target-owned, adapter-bound progr...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

docs/SPEC_edict-lawpack-abi-v1.md

[grammar] ~269-~269: Ensure spelling is correct
Context: ...udget maps must exactly cover the owning lawpack's exported operation profiles, runtime ef...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

fixtures/lawpack/causal-cell/README.md

[style] ~17-~17: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...le capability surface. - adapter.cbor and adapter.sha256 bind the direct declar...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~18-~18: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: .... - echo-operation-configuration.cbor and its digest sidecar bind the generic E...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

docs/topics/cli/README.md

[grammar] ~28-~28: Ensure spelling is correct
Context: ...es one exact Edict source, its complete lawpack closure, the selected target profile an...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

docs/topics/lawpacks/README.md

[grammar] ~38-~38: Ensure spelling is correct
Context: ...rrent executable Rust surfaces touching lawpacks are: - parser support for `ImportKind:...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

CHANGELOG.md

[grammar] ~35-~35: Ensure spelling is correct
Context: ...elected and digest-bound by a validated lawpack, must completely discharge exported o...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🔇 Additional comments (77)
crates/edict-syntax/src/parser.rs (1)

121-121: LGTM!

crates/edict-syntax/tests/lawpack.rs (1)

1-927: LGTM!

crates/edict-syntax/src/lawpack.rs (5)

331-370: LGTM!

Also applies to: 382-466


468-655: LGTM!


657-723: LGTM!


1150-1665: LGTM!


1667-1946: LGTM!

crates/edict-syntax/src/lib.rs (1)

79-80: LGTM!

Also applies to: 139-153

crates/edict-syntax/src/lawpack_adapter.rs (1)

159-191: LGTM!

Also applies to: 268-300, 403-475, 477-528, 530-586, 613-637

docs/abi/edict-lawpack-adapter.cddl (1)

1-45: LGTM!

Also applies to: 48-49

docs/abi/edict-target-profile.cddl (1)

33-36: LGTM!

fixtures/provider-contracts/v1/edict-provider-contracts.cddl (1)

539-584: LGTM!

Also applies to: 587-589, 623-626

docs/topics/lawpacks/README.md (1)

8-12: LGTM!

Also applies to: 34-52, 64-86, 107-110

docs/topics/lawpacks/test-plan.md (1)

10-22: LGTM!

Also applies to: 33-35, 45-73, 75-76, 85-96

docs/topics/fixtures/test-plan.md (1)

14-21: LGTM!

Also applies to: 31-36, 56-57, 66-71, 85-85

docs/topics/compiler-spine/test-plan.md (1)

52-52: LGTM!

Also applies to: 87-87

docs/topics/contract-bundles/README.md (2)

73-82: LGTM!


83-83: 📐 Maintainability & Code Quality

No change needed. [BUNDLE-REQ-010] is defined in docs/topics/contract-bundles/test-plan.md and cited by BUNDLE-TP-016.

crates/edict-syntax/src/target_profile.rs (2)

8-8: LGTM!

Also applies to: 159-169


70-70: 📐 Maintainability & Code Quality

Call out the public API break from this variant rename.

TargetProfileConformanceFailureKind is re-exported by crates/edict-syntax/src/lib.rs; replacing DeferredLawpackAdapterAbiUnsupported with UnsupportedLawpackAdapterAbi breaks downstream exhaustive matches. Please record the breaking rename/migration in CHANGELOG.md and confirm it is intentional for this release line.

CHANGELOG.md (1)

13-46: LGTM!

Also applies to: 68-78

docs/REQUIREMENTS.md (1)

90-90: LGTM!

docs/SPEC_edict-lawpack-abi-v1.md (1)

267-274: LGTM!

docs/SPEC_edict-target-profile-abi-v1.md (1)

101-116: LGTM!

docs/topics/contract-bundles/test-plan.md (1)

46-48: LGTM!

Also applies to: 71-77

docs/topics/target-ir/test-plan.md (1)

55-55: LGTM!

Also applies to: 107-107

docs/topics/target-profiles/README.md (1)

58-58: LGTM!

Also applies to: 69-72

docs/topics/target-profiles/test-plan.md (1)

14-14: LGTM!

Also applies to: 48-48, 72-72

crates/edict-syntax/tests/target_profile.rs (1)

10-10: LGTM!

Also applies to: 42-42, 133-154

crates/edict-provider-schema/src/contract_pack.rs (1)

35-38: LGTM!

Also applies to: 72-72, 296-296, 306-306

crates/edict-provider-schema/src/recursive_dispatch.rs (2)

262-264: LGTM!

Traced required_key_choice against REQUIRED_KEY_RECURSIVE_SCHEMA in registry.rs line by line: the discriminator search correctly fails closed on optional/overlapping/wildcard keys (exact_text_map_key_requirements rejects non-literal keys and duplicate-in-arm keys outright), and the "required-in-exactly-one-arm, absent-from-the-other" criterion is sound given CDDL's closed-map default (an arm that doesn't declare the key can never validate a value that carries it).

Also applies to: 457-463, 490-539


688-704: LGTM!

Verified against recursive_required_key_dispatch_accepts_compatible_untagged_arms and checked_target_ir_root_constructs_through_required_key_dispatch in crates/edict-provider-schema/tests/registry.rs — presence/absence dispatch and the >1-occurrence rejection both match expected outcomes for closed/legacy and nested-child cases.

crates/edict-provider-schema/tests/provider_contract_pack.rs (1)

28-28: LGTM!

Contract-count bump and new lawpack-adapter fixture/representative-instance wiring are consistent with contract_pack.rs's CONTRACT_BINDINGS extension.

Also applies to: 41-42, 74-74, 518-518, 566-570

crates/edict-provider-schema/tests/registry.rs (1)

35-47: LGTM!

REQUIRED_KEY_RECURSIVE_SCHEMA's closed/legacy arms share the non-discriminating kind: "artifact" field on purpose, exercising the code path that must skip over shared-but-non-discriminating required keys before landing on semanticClosure/value as the true discriminator. Good coverage of the recursive nested-child case too.

Also applies to: 629-666

crates/edict-syntax/tests/contract_bundle.rs (1)

376-376: LGTM!

Traced each new/updated test against the corresponding corroborate_target_ir_semantic_closure match arm in contract_bundle.rs: exact provider-supplied closure acceptance, Core-substitution rejection, lawpack-substitution rejection, missing-closure rejection, and the updated source_core-specific error field on the mismatched-closure case all line up with the actual control flow.

Also applies to: 477-504, 727-800, 819-828

docs/topics/providers/test-plan.md (1)

144-144: LGTM!

PROVIDERS-TP-048's expanded failure-category list and the two newly cited case IDs (recursive_required_key_dispatch_accepts_compatible_untagged_arms, checked_target_ir_root_constructs_through_required_key_dispatch) match the new tests added in crates/edict-provider-schema/tests/registry.rs in this same change, satisfying the requirement to update the test plan alongside the behavior it documents.

docs/topics/cli/test-plan.md (2)

45-45: The overclaimed implemented status on CLI-REQ-015 is already covered in my note on crates/edict-cli/tests/jsonl_cli.rs Lines 57-82, where the missing evidence actually lives.


16-24: LGTM!

Also applies to: 114-115

crates/edict-cli/src/application_build.rs (7)

29-78: LGTM!


383-420: LGTM!


422-460: LGTM!

Also applies to: 462-485


872-969: LGTM!


1096-1122: LGTM!


311-339: 🎯 Functional Correctness

No change needed: ValidatedTargetProviderManifest<'_> is Copy, so the double by-value use is legal.


971-996: 🔒 Security & Privacy

No changes needed: the digest comparison is domain-framed and string-rendered consistently.

manifest_artifact.resource.digest is only validated as a lowercase sha256: hex string; the code does not publish a plain artifact-byte digest semantics claim, and the provider digest path uses CORE_DIGEST_FRAME, TARGET_PROFILE_API_VERSION, and rendered_digest formatting is lowercase in edict-cli.

docs/schemas/edict.compiler-settings.v1.schema.json (1)

13-23: LGTM!

docs/topics/cli/README.md (1)

87-94: LGTM!

Also applies to: 124-126, 144-148

fixtures/lawpack/hello-echo/manifest.sha256 (1)

1-1: LGTM!

fixtures/provider-contracts/v1/manifest.json (1)

6-12: 🗄️ Data Integrity & Integration

Generated artifact digest is consistent.

fixtures/providers/components/inventory.json (1)

10-10: 🗄️ Data Integrity & Integration

No change needed. The sourceDigest is a valid sha256: + 64 lowercase hex value, and it is not the only sourceDigest change in the repo.

fixtures/lawpack/hello-echo/create-greeting.edict (1)

1-31: LGTM!

fixtures/lawpack/hello-echo/create-greeting.target-ir.cbor (1)

1-1: LGTM!

fixtures/lawpack/hello-echo/create-greeting.target-ir.sha256 (1)

1-1: LGTM!

fixtures/lawpack/hello-echo/echo-operation-configuration.cbor (1)

1-1: LGTM!

fixtures/lawpack/hello-echo/echo-operation-configuration.sha256 (1)

1-1: LGTM!

fixtures/lawpack/hello-echo/exports.cbor (1)

1-1: LGTM!

fixtures/lawpack/hello-echo/exports.sha256 (1)

1-1: LGTM!

fixtures/lawpack/hello-echo/manifest.cbor (1)

1-1: LGTM!

xtask/src/main.rs (1)

6-6: LGTM!

Also applies to: 26-26, 95-95, 134-134, 154-165, 206-206

fixtures/lawpack/causal-cell/exports.sha256 (1)

1-2: LGTM!

fixtures/lawpack/causal-cell/manifest.cbor (1)

1-2: LGTM!

fixtures/lawpack/causal-cell/manifest.sha256 (1)

1-2: LGTM!

fixtures/lawpack/hello-echo/README.md (1)

1-48: LGTM!

fixtures/lawpack/hello-echo/adapter.cbor (1)

1-2: LGTM!

fixtures/lawpack/hello-echo/adapter.sha256 (1)

1-2: LGTM!

fixtures/lawpack/hello-echo/create-greeting.core.cbor (1)

1-1: LGTM!

fixtures/lawpack/hello-echo/create-greeting.core.sha256 (1)

1-2: LGTM!

xtask/src/provider_contract_pack.rs (1)

12-12: LGTM!

Also applies to: 34-42

xtask/src/tests.rs (1)

29-29: LGTM!

Also applies to: 75-80, 140-140, 275-275

fixtures/README.md (1)

47-48: LGTM!

fixtures/lawpack/causal-cell/README.md (2)

3-4: 📐 Maintainability & Code Quality

Verify the claimed standalone consumer.

The supplied implementation shows causal_cell_golden_artifacts using this fixture to compile an internal source witness, while the standalone Hello Echo build evidence uses fixtures/lawpack/hello-echo/. Please either identify the actual standalone consumer or describe this fixture as generator-validated; otherwise users may treat an internal golden as a currently supported application input.

Also applies to: 33-37


1-2: LGTM!

Also applies to: 5-32

fixtures/lawpack/causal-cell/adapter.cbor (1)

1-1: LGTM!

fixtures/lawpack/causal-cell/adapter.sha256 (1)

1-1: LGTM!

fixtures/lawpack/causal-cell/echo-operation-configuration.cbor (1)

1-1: LGTM!

fixtures/lawpack/causal-cell/echo-operation-configuration.sha256 (1)

1-1: LGTM!

fixtures/lawpack/causal-cell/exports.cbor (1)

1-1: LGTM!

Comment thread crates/edict-cli/Cargo.toml Outdated
Comment thread crates/edict-cli/src/application_build.rs Outdated
Comment thread crates/edict-cli/src/application_build.rs
Comment thread crates/edict-cli/src/application_build.rs
Comment thread crates/edict-cli/src/application_build.rs
Comment thread docs/abi/edict-lawpack-adapter.cddl Outdated
Comment thread docs/topics/cli/README.md
Comment thread docs/topics/cli/test-plan.md Outdated
Comment thread docs/topics/lawpacks/test-plan.md Outdated
Comment thread xtask/src/lawpack_goldens.rs Outdated
@flyingrobots

Copy link
Copy Markdown
Owner Author

@codex please review

@flyingrobots

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 8

♻️ Duplicate comments (1)
crates/edict-cli/src/application_build.rs (1)

705-713: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Every diagnostic is still a hanging offence.

ProviderDiagnosticSeverity exists; you advertise max_diagnostic_count in response_limits(); and then any single info-severity note from the lowerer kills the build with ProviderLowererFailed. Same shape at Lines 815-823 for the verifier, where it is escalated all the way to ProviderVerificationRejected. Gate on the severities that are actually contracted to block.

🤖 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/edict-cli/src/application_build.rs` around lines 705 - 713, Update the
lowerer error handling around the diagnostic check to reject only diagnostics
whose ProviderDiagnosticSeverity is contractually blocking, while allowing
informational and other non-blocking diagnostics and preserving the existing
failure response for blocking ones. Apply the same severity-aware filtering to
the verifier path that currently returns ProviderVerificationRejected, using the
advertised max_diagnostic_count contract rather than treating any non-empty
diagnostics collection as fatal.
🤖 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 `@crates/edict-cli/src/application_build.rs`:
- Around line 1686-1691: Update the resource fixture helper resource so digest
constructs the sha256 prefix once and repeats only the two-character hexadecimal
digest body 32 times, producing a valid 64-character digest while preserving the
existing ResourceRef behavior.
- Around line 1160-1185: Update the application output locking flow around
lock_path and try_lock so the published output never retains
.edict-application-build.lock. Prefer writing the build into a uniquely created
temporary output directory and atomically renaming it into place after success,
while preserving contention failures; alternatively, ensure production cleanup
always removes the lock file before completion.

In `@crates/edict-cli/tests/jsonl_cli.rs`:
- Around line 87-145: Update
build_rejects_compiler_input_records_instead_of_ignoring_them and
build_rejects_unused_directory_extension_settings to reference the
guaranteed-missing application path under temp_tree, matching the sibling test
setup. Remove both temporary trees at the end of each test, consistent with the
cleanup at line 84. In build_rejects_unused_directory_extension_settings, also
assert the diagnostic command is "build" alongside the existing kind assertion.

In `@crates/edict-syntax/src/lawpack.rs`:
- Around line 761-821: The raw recursion in validate_pure_callees_in_value
incorrectly interprets arbitrary literal maps as call expressions. Replace this
scan with traversal of parsed expression/predicate nodes used by
validate_pure_function_callees, validating callee coordinates only for actual
call nodes; ensure traversal does not recurse into const.value literal contents
as executable syntax.

In `@crates/edict-syntax/src/target_ir.rs`:
- Around line 686-699: Update the obstruction lowering in `lower_to_target_ir`
so mapped failures resolving to the same target coordinate, including collisions
with unmapped failure names, are detected before collecting into `BTreeMap`.
Reject the lowering explicitly with the existing failure/error path, ensuring
`unsupported_obstructions` and artifact emission are not reached with a
deduplicated map.

In `@crates/edict-syntax/tests/provider.rs`:
- Around line 253-271: Update provider_manifest_rejects_path_like_artifact_roles
to assert the report’s failure_kinds contains UnsafeArtifactRole for the
artifacts.role field path, rather than only checking Invalid. Reuse the existing
failure_kinds structure and extend unsafe_role cases to cover colon-containing
and control-character roles, preserving the current path-like cases.

In `@docs/topics/cli/test-plan.md`:
- Line 45: Update the CLI-REQ-015 status in the test plan to partial/planned
unless executable repository-owned evidence exists for the complete build flow.
If implementing it, add the missing CLI-TP-028 end-to-end fixture and test
covering closure validation, provider lowering, independent verification, and
accepted package/report publication, then retain implemented status only with
that evidence.

In `@xtask/src/tests.rs`:
- Around line 1999-2006: Update assert_compiler_settings_projection_properties
to compare the projected emit enum against the exact expected list, including
its ordering, rather than merely checking that each value is present. Preserve
the existing operation assertion’s exact-contract behavior and use the expected
values syntax, diagnostics, core, targetIr, and digests.

---

Duplicate comments:
In `@crates/edict-cli/src/application_build.rs`:
- Around line 705-713: Update the lowerer error handling around the diagnostic
check to reject only diagnostics whose ProviderDiagnosticSeverity is
contractually blocking, while allowing informational and other non-blocking
diagnostics and preserving the existing failure response for blocking ones.
Apply the same severity-aware filtering to the verifier path that currently
returns ProviderVerificationRejected, using the advertised max_diagnostic_count
contract rather than treating any non-empty diagnostics collection as fatal.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1f9089e6-5417-490a-88ba-7f0a43ff7f65

📥 Commits

Reviewing files that changed from the base of the PR and between 49173d8 and 2e3f52f.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (36)
  • CHANGELOG.md
  • crates/edict-cli/Cargo.toml
  • crates/edict-cli/src/application_build.rs
  • crates/edict-cli/src/main.rs
  • crates/edict-cli/tests/jsonl_cli.rs
  • crates/edict-syntax/src/authority_facts.rs
  • crates/edict-syntax/src/canonical.rs
  • crates/edict-syntax/src/contract_bundle.rs
  • crates/edict-syntax/src/lawpack.rs
  • crates/edict-syntax/src/lawpack_adapter.rs
  • crates/edict-syntax/src/lib.rs
  • crates/edict-syntax/src/provider.rs
  • crates/edict-syntax/src/target_ir.rs
  • crates/edict-syntax/tests/contract_bundle.rs
  • crates/edict-syntax/tests/lawpack.rs
  • crates/edict-syntax/tests/operation_prerequisites.rs
  • crates/edict-syntax/tests/provider.rs
  • crates/edict-syntax/tests/provider_lowering.rs
  • crates/edict-syntax/tests/target_ir.rs
  • docs/abi/edict-lawpack-adapter.cddl
  • docs/schemas/edict.compiler-settings.v1.schema.json
  • docs/topics/cli/README.md
  • docs/topics/cli/test-plan.md
  • docs/topics/lawpacks/test-plan.md
  • fixtures/lawpack/causal-cell/adapter.cbor
  • fixtures/lawpack/causal-cell/adapter.sha256
  • fixtures/lawpack/causal-cell/manifest.cbor
  • fixtures/lawpack/causal-cell/manifest.sha256
  • fixtures/lawpack/hello-echo/create-greeting.target-ir.cbor
  • fixtures/lawpack/hello-echo/create-greeting.target-ir.sha256
  • fixtures/provider-contracts/v1/edict-provider-contracts.cddl
  • fixtures/provider-contracts/v1/manifest.json
  • fixtures/providers/components/inventory.json
  • xtask/src/goldens.rs
  • xtask/src/lawpack_goldens.rs
  • xtask/src/tests.rs
💤 Files with no reviewable changes (1)
  • crates/edict-cli/Cargo.toml
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: rust msrv 1.94.0 (fmt · clippy · test)
  • GitHub Check: supply-chain (cargo-deny)
  • GitHub Check: rust stable (fmt · clippy · test)
🧰 Additional context used
📓 Path-based instructions (2)
docs/topics/**/{README.md,test-plan.md,architecture.md,rationale.md}

📄 CodeRabbit inference engine (AGENTS.md)

docs/topics/**/{README.md,test-plan.md,architecture.md,rationale.md}: For every nontrivial behavior, contract, workflow, release, schema, validation, or public-surface change, identify the owning topic shelf before editing code; create one if none exists; update test-plan.md before or alongside tests with requirement IDs, case IDs, fixtures, and oracles; write executable evidence; update the topic README.md only after behavior exists; mark planned cases implemented only when executable evidence exists; and run cargo xtask verify before claiming the shelf is current.
Do not churn topic shelves for purely mechanical edits that do not change a contract; when a change intentionally does not update a topic shelf, state why in the pull request body or final report.
Topic README.md files must not describe intended behavior before it lands; test-plan.md may include planned cases and known gaps; policy rows are for human-review workflow contracts and must not be used to avoid writing behavior tests; tests must assert code behavior and stable contract artifacts, not prose; negative tests should assert stable error kinds or structured artifacts, not merely is_err() or diagnostic text; release, CI, and publication workflows count as behavior when they define a project contract; avoid ceremonial documentation and update shelves because the contract changed, not because a path changed.

Files:

  • docs/topics/cli/test-plan.md
  • docs/topics/cli/README.md
  • docs/topics/lawpacks/test-plan.md
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

When creating or changing documentation, give each page one primary reader job; keep user-facing task help separate from contributor architecture and evidence maps; use concrete, valid examples and show expected results when the result matters; put exact public facts in reference material and validate or generate them from authoritative sources when practical; and update affected documentation in the same change as behavior, schema, release, workflow, or public-surface changes, or state docs-impact: none with a concise rationale.

Files:

  • docs/topics/cli/test-plan.md
  • docs/topics/cli/README.md
  • docs/topics/lawpacks/test-plan.md
🔇 Additional comments (47)
crates/edict-syntax/tests/operation_prerequisites.rs (1)

52-52: LGTM!

crates/edict-syntax/tests/provider_lowering.rs (2)

98-98: LGTM!


137-137: LGTM!

crates/edict-syntax/tests/target_ir.rs (4)

231-231: LGTM!


248-248: LGTM!


694-699: LGTM!


950-950: LGTM!

crates/edict-syntax/tests/lawpack.rs (3)

141-150: LGTM!


226-245: LGTM!


535-592: LGTM!

docs/topics/cli/README.md (2)

36-38: 🎯 Functional Correctness

Verify the build discriminator before publishing this example.

Line 37 still uses "type":"compilerSettings", while this route is documented as a settings-only record. The prior dispatcher contract reportedly requires "type":"settings"; if that remains true, this copy-paste example is rejected before the build starts. Align the example and its golden fixture with the actual dispatcher contract.

As per coding guidelines, documentation must use concrete, valid examples and exact public facts.

rg -n -C 4 'InvalidSettings|compilerSettings|type.*settings|operation.*build' crates/edict-cli/src/main.rs docs/schemas/edict.compiler-settings.v1.schema.json

Source: Coding guidelines


24-35: LGTM!

Also applies to: 40-80, 123-130, 160-162, 180-181

crates/edict-syntax/src/provider.rs (1)

134-134: LGTM!

Also applies to: 253-259, 342-347

crates/edict-syntax/tests/contract_bundle.rs (1)

376-376: LGTM!

Also applies to: 477-504, 543-543, 728-738, 741-763, 765-783, 786-798, 801-829

crates/edict-syntax/src/contract_bundle.rs (1)

575-607: LGTM!

Also applies to: 625-627

docs/abi/edict-lawpack-adapter.cddl (1)

1-49: LGTM!

fixtures/provider-contracts/v1/edict-provider-contracts.cddl (1)

539-589: LGTM!

Also applies to: 623-626

docs/topics/lawpacks/test-plan.md (1)

10-22: LGTM!

Also applies to: 33-35, 45-53, 54-62, 63-76, 85-96

CHANGELOG.md (1)

11-18: LGTM!

Also applies to: 77-87

docs/topics/cli/test-plan.md (1)

100-100: Document the Hello Echo fixture corpus and its oracle.

The referenced Hello Echo integration witness still has no corresponding Fixtures-table row linking its lawpack artifacts to cargo xtask lawpack-goldens --check.

As per coding guidelines, “update test-plan.md before or alongside tests with requirement IDs, case IDs, fixtures, and oracles”.

Source: Coding guidelines

crates/edict-syntax/src/authority_facts.rs (1)

16-17: LGTM!

crates/edict-syntax/src/canonical.rs (1)

187-211: LGTM!

crates/edict-syntax/src/lawpack.rs (1)

12-13: LGTM!

crates/edict-syntax/src/lib.rs (1)

79-80: LGTM!

Also applies to: 110-115, 139-153

docs/schemas/edict.compiler-settings.v1.schema.json (1)

17-22: LGTM!

Also applies to: 175-222

fixtures/lawpack/causal-cell/manifest.sha256 (1)

1-1: LGTM!

fixtures/lawpack/hello-echo/create-greeting.target-ir.cbor (1)

1-1: LGTM!

fixtures/lawpack/hello-echo/create-greeting.target-ir.sha256 (1)

1-1: LGTM!

fixtures/provider-contracts/v1/manifest.json (1)

6-12: LGTM!

fixtures/providers/components/inventory.json (1)

10-10: LGTM!

crates/edict-syntax/src/lawpack_adapter.rs (2)

11-13: LGTM!

Also applies to: 230-240, 721-732


365-368: LGTM!

Also applies to: 480-543, 654-670

crates/edict-syntax/src/target_ir.rs (1)

113-117: LGTM!

Also applies to: 119-135

crates/edict-cli/src/application_build.rs (5)

113-119: LGTM!

Also applies to: 154-159


366-445: LGTM!


606-624: LGTM!

Also applies to: 957-996


1186-1296: LGTM!

Also applies to: 1298-1416


1470-1685: LGTM!

Also applies to: 1692-1716

crates/edict-cli/src/main.rs (1)

378-385: LGTM!

Also applies to: 423-423, 486-534, 1078-1078

crates/edict-cli/tests/jsonl_cli.rs (1)

58-85: LGTM!

Also applies to: 1312-1312

xtask/src/tests.rs (1)

1984-1998: LGTM!

Also applies to: 2045-2075

xtask/src/lawpack_goldens.rs (2)

59-59: 🗄️ Data Integrity & Integration | ⚡ Quick win

Correct fix — now prove the other fixture did not inherit the same bug.

Framing the configuration digest with the declared coordinate is right, and it matches crates/edict-cli/src/application_build.rs Line 616, which recomputes it as provider_digest(&reference.id, bytes). The causal-cell adapter fixture agrees: its targetConfiguration.id is echo.operation-lowering-configuration/v1.

Two things I want evidence for before this is closed. First, that TARGET_CONFIGURATION_COORDINATE used at Line 423 is byte-identical to whatever hello_echo_adapter writes into targetConfiguration.id — that is the exact mismatch you just repaired for causal-cell, and the Hello Echo path is the one the CLI actually builds. Second, CAUSAL_CELL_CONFIGURATION_COORDINATE no longer names a causal-cell-specific resource; if both fixtures now declare the same configuration coordinate over different bytes, two distinct digests are framed under one domain. Legal, but the constant's name is now a lie and the collision should be deliberate.

#!/bin/bash
# What coordinate constants exist, and what do the adapter builders actually emit?
rg -nP -C2 '(CAUSAL_CELL_)?(TARGET_)?CONFIGURATION_COORDINATE\s*:\s*&str' xtask/src/lawpack_goldens.rs
ast-grep run --pattern 'fn hello_echo_adapter($$$) { $$$ }' --lang rust xtask/src/lawpack_goldens.rs
ast-grep run --pattern 'fn causal_cell_adapter($$$) { $$$ }' --lang rust xtask/src/lawpack_goldens.rs

# Same coordinate declared by both fixtures?
rg -na -o 'echo\.operation-lowering-configuration/v1' fixtures/lawpack

Also applies to: 99-100


90-152: LGTM!

Also applies to: 414-495

fixtures/lawpack/causal-cell/adapter.cbor (1)

1-1: LGTM!

fixtures/lawpack/causal-cell/adapter.sha256 (1)

1-1: LGTM!

fixtures/lawpack/causal-cell/manifest.cbor (1)

1-2: LGTM!

xtask/src/goldens.rs (1)

349-364: LGTM!

Also applies to: 366-381

Comment thread crates/edict-cli/src/application_build.rs
Comment thread crates/edict-cli/src/application_build.rs
Comment thread crates/edict-cli/tests/jsonl_cli.rs
Comment thread crates/edict-syntax/src/lawpack.rs
Comment thread crates/edict-syntax/src/target_ir.rs Outdated
Comment thread crates/edict-syntax/tests/provider.rs
Comment thread docs/topics/cli/test-plan.md Outdated
Comment thread xtask/src/tests.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2e3f52f9e6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/edict-cli/src/application_build.rs
Comment thread crates/edict-cli/src/application_build.rs
Comment thread crates/edict-cli/src/main.rs
Comment thread crates/edict-cli/src/application_build.rs Outdated
Comment thread crates/edict-syntax/src/target_ir.rs Outdated
@flyingrobots

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@flyingrobots

Copy link
Copy Markdown
Owner Author

@codex please review

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@flyingrobots

Copy link
Copy Markdown
Owner Author

Merge gate OPEN at 0595abf. All CI checks pass; no review thread is unresolved; Code Lawyer outcomes are FIXED, DEFERRED, UNREPRODUCIBLE, or STALE; cargo xtask verify and the external Hello Echo build are clean. The main ruleset requires zero approving reviews, so these criteria substitute for human approval in this solo-maintained repository.

@flyingrobots
flyingrobots merged commit 296bf1f into main Jul 28, 2026
4 checks passed
@flyingrobots
flyingrobots deleted the task/169-compile-standalone-hello-echo branch July 28, 2026 17:30

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

input_depth,
requires_dispatch,
)?;
recursive_alternatives += usize::from(option_reenters);

P2 Badge Update the recursive-schema contract for required-key dispatch

This change newly admits recursive alternatives selected by the presence of a required key, but the providers topic README still states that every recursive alternative must expose one common singleton text discriminator and that missing discriminators reject. That is now false for the checked Target IR union, leaving the repository's current-contract documentation inconsistent with executable behavior; document the bounded two-arm required-key exception alongside the implementation.

AGENTS.md reference: AGENTS.md:L58-L60

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +873 to +874
coordinate: required_nonempty_text(&fields, "coordinate", path)?,
definition: required_nonempty_text(&fields, "definition", path)?,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Parse and enforce bounded exported types

When a lawpack supplies an unbounded or otherwise invalid definition such as String, this branch accepts it solely because the text is non-empty and returns it from ValidatedLawpackBundle; the same opaque-string treatment is used for constant, parameter, return, effect, and payload types. Such a bundle bypasses the lawpack ABI's bounded Core-type contract and can expose unbounded values to compilation or provider processing, so these fields need to be parsed and validated against the bounded Core type universe before the bundle is considered valid.

Useful? React with 👍 / 👎.

Comment on lines +250 to +254
target_profile: ResourceRef {
coordinate: adapter.target_profile().id.clone(),
digest: Some(adapter.target_profile().digest_review_string()),
},
target_ir_domain: adapter.target_ir().id.clone(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Corroborate the accepted Target IR digest

When a lawpack manifest's acceptedTargetIr.digest is substituted and the manifest/source import are re-digested, preparation still succeeds because only the reference ID is copied into target_ir_domain; the digest is never consumed anywhere in the build path. Consequently the purportedly digest-locked Target IR ABI can be changed without affecting compilation or rejection, so the descriptor's complete resource identity must be compared with the selected target profile's Target IR identity before deriving trusted lowering facts.

Useful? React with 👍 / 👎.

Comment on lines +162 to +167
let loaded = loaded_lawpacks.first().ok_or_else(|| {
failure(
"InvalidApplicationConfig",
"the executable-operation build requires a root lawpack",
)
})?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Bind the complete lawpack closure into provider requests

For an application whose root lawpack has dependencies, the graph validates their manifests and digests but this selection discards every loaded entry except the first; compilation and both provider semantic-input builders subsequently receive only that root's manifest, exports, adapter, and configuration. The lowerer and independent verifier therefore cannot bind or inspect the dependency bytes even though the CLI reports that the complete referenced closure was checked, so all reachable closure artifacts must be carried into the compilation/provider contracts rather than reduced to one LoadedLawpack.

Useful? React with 👍 / 👎.

Comment on lines +100 to +101
| CLI-TP-027 | implemented | Build request dispatch | CLI-REQ-015 | A `build` settings record is accepted without compiler input records and reaches application-config loading; a missing application config fails as a structured `ApplicationConfigReadFailed` build diagnostic rather than as invalid settings or missing compiler input. | build_accepts_application_request_without_compiler_input_records | crates/edict-cli/tests/jsonl_cli.rs | Covers the public request shape and dispatch boundary only. |
| CLI-TP-028 | planned | Verified application build | CLI-REQ-015 | A repository-owned provider-component fixture builds one exact source and complete lawpack closure, independently accepts the package, and publishes the canonical package/report pair. | - | - | The standalone external Hello Echo build is a green integration witness; this planned case makes the full crossing reproducible inside Edict's own automated suite. |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Add the missing successful build contract test

The new public build route is described as implemented, but this row explicitly leaves its only end-to-end success case planned; the added CLI tests stop at request dispatch and missing-config rejection, so no repository-owned executable evidence invokes the lowerer/verifier or verifies successful publication and rollback behavior. Add the deterministic provider-component fixture and mark this case implemented only after it passes, as required for nontrivial behavior claims.

AGENTS.md reference: AGENTS.md:L49-L60

Useful? React with 👍 / 👎.

Comment on lines +230 to +234
for (coordinate, effect) in &adapter.effects {
let local_effect = local_coordinate(&alias, &prefix, coordinate)?;
compiler_context = compiler_context
.with_effect_write_class(local_effect.clone(), effect.write_class.clone());
obstruction_coordinates.extend(effect.failure_mappings.values().cloned());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Enforce declared effect-failure coverage in source handlers

When an exported effect declares multiple named failures, preparation gives the compiler only its write class and never supplies the declared failure set or authority classes. A source can therefore handle only one failure, or author-map a non-domain-mappable failure, and still compile and lower successfully because Target IR includes only the arms that happened to appear in source; the resulting package has no behavior for the omitted provider failure. Propagate the exact exported failure contract into compiler checking and require exhaustive, authority-valid handlers before emitting Core.

Useful? React with 👍 / 👎.

Comment on lines +327 to +330
let lowerer_artifact =
unique_artifact(&provider_manifest, ProviderArtifactKind::Lowerer, None)?;
let verifier_artifact =
unique_artifact(&provider_manifest, ProviderArtifactKind::Verifier, None)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Select components authorized by the target profile

For a provider package whose sole lowerer or verifier differs from the digest-locked component references inside the selected target profile, these lookups still choose those package components solely by artifact kind. The host verifies each component against the provider manifest, but nothing corroborates that it is the lowerer or verifier authorized by the selected profile; valid multi-component packages are also rejected rather than resolved through those profile references. Decode the selected profile and use its exact lowerer/verifier resource identities to select and verify the invocation components.

Useful? React with 👍 / 👎.

Comment on lines +1300 to +1305
"local" => {
ensure_allowed_fields(fields, path, &["kind", "ref"]).map_err(as_pure_body_failure)?;
validate_local_ref(
required(fields, "ref", path).map_err(as_pure_body_failure)?,
&format!("{path}.ref"),
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Validate local references in pure helper bodies

When a pure helper expression contains a structurally valid local reference whose ID was never declared as a parameter, local, or preceding binding, this branch accepts it because validate_local_ref checks only that its three strings are non-empty. It likewise accepts a reused ID with a conflicting alpha name or type, so ValidatedLawpackBundle can expose a supposedly total Core helper that cannot be evaluated deterministically. Track the function scope and require every reference to match exactly one in-scope declaration before accepting the body.

Useful? React with 👍 / 👎.

Comment on lines +148 to +150
let mut loaded_lawpacks = Vec::with_capacity(config.lawpacks.len());
for lawpack in &config.lawpacks {
loaded_lawpacks.push(load_lawpack(&root, lawpack)?);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Bound the aggregate lawpack closure before loading it

A build manifest can fit thousands of repeated lawpack entries inside the 1 MiB config limit, and this loop loads four independently permitted 1 MiB artifacts for every entry before duplicate identities or graph validity are checked. A crafted local project can therefore force multi-gigabyte allocation and I/O even though each individual read is bounded. Impose a closure-count and aggregate-byte limit, and reject duplicates before retaining all artifact buffers.

Useful? React with 👍 / 👎.

Comment on lines +1602 to +1607
"int" => {
ensure_allowed_fields(fields, path, &["kind", "width", "value"])
.map_err(as_pure_body_failure)?;
required_nonempty_text(fields, "width", path).map_err(as_pure_body_failure)?;
match required(fields, "value", path).map_err(as_pure_body_failure)? {
CanonicalValue::Integer(_) => Ok(()),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Validate Core integer widths and ranges in helper bodies

For an inline pure helper containing an integer constant such as {kind: "int", width: "U8", value: 256} or an unknown width, this branch accepts the value because it checks only for non-empty width text and an integer-shaped value. The canonical Core encoder rejects these values through parse_core_integer, so the lawpack loader can currently return a validated helper body that cannot correspond to valid canonical Core. Apply the same supported-width and range validation before accepting the helper.

Useful? React with 👍 / 👎.

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.

Compile standalone Hello Echo through the provider boundary

1 participant