Skip to content

Lower obstruction continuations into Core - #130

Merged
flyingrobots merged 7 commits into
mainfrom
core/obstruction-strand-ir
Jul 5, 2026
Merged

Lower obstruction continuations into Core#130
flyingrobots merged 7 commits into
mainfrom
core/obstruction-strand-ir

Conversation

@flyingrobots

Copy link
Copy Markdown
Owner

Summary

Lower parsed obstruction-strand require arms into explicit Core require nodes.

This PR implements the Core slice for obstruction strands:

  • adds CoreNode::Require;
  • adds CoreRequireFailureArm::Terminal and CoreRequireFailureArm::ContinueObstructed;
  • adds a closed CoreObstructionReason envelope with stable reason kind plus canonical payload map;
  • canonicalizes the require-failure disposition, reason kind, and payload into Core bytes/digests;
  • rejects duplicate preserved-obstruction payload fields before Core digesting;
  • keeps Target IR support explicitly unsupported for Core require nodes until the next slice.

Closes #129
Refs #116

Claims

  • Source syntax parses; landed in Parse obstruction strand continuations #128.
  • Core semantics implemented for the currently lowerable require subset.
  • Terminal require obstruction and continue obstructed are Core-distinct.
  • Core digests bind require-failure disposition, reason kind, and payload values.
  • Echo Target IR lowering implemented.
  • Echo runtime execution implemented.
  • Graft/jedit projection implemented.
  • Scheduler admission/counterfactual semantics implemented.
  • Continuum settlement implemented.

Explicit Non-Goals

  • No Target IR obstruction-strand lowering.
  • No Echo acceptance or execution receipt.
  • No scheduler counterfactual model.
  • No Graft or jedit display behavior.
  • No canonical Echo receipt bytes or digest.
  • No support-tier or settlement claim.

RED

cargo test -p edict-syntax --test compiler_spine obstruction

Observed failure before implementation: missing CoreNode::Require, CoreRequireFailureArm, CoreObstructionReason, and DuplicateObstructionPayloadField.

GREEN

cargo test -p edict-syntax --test compiler_spine obstruction
cargo test -p edict-syntax --test compiler_spine
cargo test -p edict-syntax --test canonical_encoding
cargo test -p edict-syntax --test target_ir unsupported_core_node
cargo xtask contract-check
cargo xtask verify

Docs

Updated the Core ABI CDDL, compiler-spine shelf, Core IR shelf, obstruction-strands shelf, syntax test-plan note, fixture corridor note, design note, topics index, and changelog.

@coderabbitai

coderabbitai Bot commented Jul 5, 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: 50 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

Run ID: 1e470b1e-a030-4fe4-902e-e498d795f56a

📥 Commits

Reviewing files that changed from the base of the PR and between 1b7e835 and a711a2e.

📒 Files selected for processing (2)
  • crates/edict-syntax/src/compiler.rs
  • crates/edict-syntax/tests/compiler_spine.rs

Walkthrough

This PR adds Core IR representation for require statement failure arms, distinguishing terminal obstruction from preserved (continue obstructed) obstruction. It wires lowering in the compiler, canonical encoding, CLI review serialization, Target IR rejection, adds compiler-spine tests, and updates the CDDL schema and extensive documentation.

Changes

Core lowering for require obstruction failure arms

Layer / File(s) Summary
Core IR require node and CDDL schema
crates/edict-syntax/src/core_ir.rs, crates/edict-syntax/src/lib.rs, docs/abi/edict-core.cddl
CoreNode::Require gains an arm: CoreRequireFailureArm field; new CoreRequireFailureArm and CoreObstructionReason types are added, re-exported, and mirrored in the CDDL schema as require-node, require-failure-arm, and obstruction-reason.
Compiler lowering of require statements
crates/edict-syntax/src/compiler.rs
check_body_stmt lowers Stmt::Require into CoreNode::Require, validating terminal payload record shape, obstruction reason kind coordinates, and payload maps while rejecting spreads and duplicate fields via new helper methods including plain_path_coordinate.
Canonical encoding of require nodes
crates/edict-syntax/src/canonical.rs
core_node_value encodes CoreNode::Require; new helpers encode require-failure arms and obstruction reason payloads deterministically.
CLI review/JSON serialization
crates/edict-cli/src/main.rs
core_node_review gets a Require arm producing JSON with predicate and onFailure; new helpers serialize failure arms/reasons; compiler_error_kind_name maps DuplicateObstructionPayloadField.
Target IR rejection of require nodes
crates/edict-syntax/src/target_ir.rs
lower_node explicitly rejects CoreNode::Require with an UnsupportedCoreNode failure detail "require".
Compiler-spine tests
crates/edict-syntax/tests/compiler_spine.rs
New fixtures, pure_context, and tests validate Core arm distinctness, digest sensitivity to reason/payload mutations, formatting invariance, and duplicate-payload rejection, with new test helpers.
Documentation, changelog, and design notes
CHANGELOG.md, docs/design/obstruction-strands-v0.md, docs/topics/..., fixtures/obstruction-strands/v0/stale-basis/README.md
Changelog, design verification/TODOs, topic shelf, compiler-spine/core-ir/obstruction-strands/syntax docs and test plans, and fixture README updated to describe the new Core require lowering scope.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Source as require ... else source
  participant Compiler as edict-syntax compiler
  participant CoreIR as CoreNode::Require
  participant Canonical as canonical encoder
  participant CLI as edict-cli review

  Source->>Compiler: parse Stmt::Require (terminal or continue obstructed)
  Compiler->>Compiler: validate predicate, reason kind, payload fields
  Compiler-->>Compiler: reject duplicate payload fields (DuplicateObstructionPayloadField)
  Compiler->>CoreIR: build CoreRequireFailureArm + CoreObstructionReason
  CoreIR->>Canonical: encode kind/predicate/onFailure into canonical map
  Canonical-->>CLI: canonical bytes consumed by review serialization
  CLI->>CLI: emit require/onFailure JSON via core_node_review
Loading

Possibly related issues

Possibly related PRs

  • flyingrobots/edict#115: Both PRs modify the same CLI Core review/projection serialization path in crates/edict-cli/src/main.rs.
  • flyingrobots/edict#128: Introduces the Stmt::Require/RequireElseArm::ContinueObstructed AST shape that this PR lowers into Core.

Poem

A rabbit dug through require's each arm,
Terminal versus obstructed, no harm—
Digests now shift when payloads misbehave,
Duplicates rejected before they're saved.
Core nodes stand distinct, canonically true. 🐇⚙️

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: lowering obstruction continuations into Core.
Description check ✅ Passed The description is directly about the implemented Core lowering and related docs/tests.
Linked Issues check ✅ Passed The changes implement the Core require-failure slice, distinct arms, digest rules, tests, and keep Target IR unsupported as required.
Out of Scope Changes check ✅ Passed No clearly unrelated code changes stand out; the docs, tests, and formatting all support the Core obstruction slice.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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-syntax/src/compiler.rs`:
- Around line 816-817: The shared payload handling in check_reason_payload is
incorrectly stripping reason for all record payloads, which causes legal payload
fields to be dropped for terminal arms. Update check_terminal_require_reason so
it preserves reason when lowering terminal records like else domain.Blocked({
reason: ... }), and limit the reason-stripping behavior to the
ContinueObstructedArm path only; use the check_reason_payload and
ContinueObstructedArm symbols to keep the fix scoped correctly.

In `@crates/edict-syntax/tests/compiler_spine.rs`:
- Around line 745-759: `assert_reason` is doing an order-sensitive comparison of
payload keys, even though it should validate the key set regardless of ordering.
Update the helper in `compiler_spine.rs` so `reason.payload` and the expected
`payload_keys` are compared in an order-independent way, using `assert_reason`
as the target and keeping the check focused on key membership rather than
iteration order.
- Around line 646-705: The digest-stability test in
obstruction_reason_mutations_move_core_digest can silently pass if the string
replace does not actually modify CONTINUE_OBSTRUCTED_REQUIRE. Update the
mutation setup for reordered_payload and reformatted to first verify the fixture
contains the expected substring before replacing it, or otherwise assert that
the mutated source differs from the baseline input. Keep the existing baseline
digest checks, but make the mutation step self-defending so the test fails when
the fixture drifts.
🪄 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

Run ID: df2ad46e-5c98-4009-aff4-74265ac40d52

📥 Commits

Reviewing files that changed from the base of the PR and between c6ddc48 and 1b7e835.

📒 Files selected for processing (20)
  • CHANGELOG.md
  • crates/edict-cli/src/main.rs
  • crates/edict-syntax/src/canonical.rs
  • crates/edict-syntax/src/compiler.rs
  • crates/edict-syntax/src/core_ir.rs
  • crates/edict-syntax/src/lib.rs
  • crates/edict-syntax/src/target_ir.rs
  • crates/edict-syntax/tests/compiler_spine.rs
  • docs/abi/edict-core.cddl
  • docs/design/obstruction-strands-v0.md
  • docs/topics/README.md
  • docs/topics/compiler-spine/README.md
  • docs/topics/compiler-spine/test-plan.md
  • docs/topics/core-ir/README.md
  • docs/topics/core-ir/canonical-encoding.md
  • docs/topics/core-ir/test-plan.md
  • docs/topics/obstruction-strands/README.md
  • docs/topics/obstruction-strands/test-plan.md
  • docs/topics/syntax/test-plan.md
  • fixtures/obstruction-strands/v0/stale-basis/README.md
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: supply-chain (cargo-deny)
🧰 Additional context used
📓 Path-based instructions (3)
**

⚙️ CodeRabbit configuration file

**: # AGENTS

Git Rules

NEVER amend git commits. Make a new commit instead.

NEVER use git rebase unless the user explicitly approves a rare exception.
Use regular merge commits.

NEVER force any git operation. If a force operation appears necessary, stop and
explain what happened and what options remain.

NEVER create draft pull requests.

NEVER use a codex prefix in branch names, PR titles, or commit messages.

Pull request bodies for issue work MUST include GitHub auto-close text such as
Closes #123`` for every issue the PR is intended to close.

Think

Think is durable memory for cross-session coordination.

  • Use codex-think --remember --json when starting a new session, changing into
    this repository, or regaining context after a context shift.
  • Use codex-think "..." --json when a cycle closes or a significant event
    should survive across turns.
  • Treat Think as memory, not repo truth. Anchor strong claims back to files,
    commits, commands, issues, or pull requests.
  • Claude memories are read-only. Use claude-think --remember --json only for
    additional context.

Topic Shelves

docs/topics/ contains the living contract graph for landed behavior. Topic
shelves are not proposals, retrospectives, or design archaeology.

Each shelf may contain:

  • README.md: what is true in HEAD.
  • test-plan.md: how those truths are verified, including requirements, cases,
    fixtures, oracles, implemented evidence, planned cases, and known gaps.
  • architecture.md: optional structure or dataflow notes when the machinery
    earns a separate page.
  • rationale.md: optional still-relevant tradeoffs and rejected approaches.

When To Update Topic Shelves

For every nontrivial behavior, contract, workflow, release, schema, validation,
or public-surface change:

  1. Identify the owning topic shelf before editing code.
  2. If no shelf owns durable behavior, create one.
  3. Update test-plan.md before or alongside tests with requirement IDs, case
    IDs,...

Files:

  • fixtures/obstruction-strands/v0/stale-basis/README.md
  • docs/topics/README.md
  • docs/topics/core-ir/README.md
  • docs/topics/syntax/test-plan.md
  • crates/edict-syntax/src/target_ir.rs
  • docs/abi/edict-core.cddl
  • docs/design/obstruction-strands-v0.md
  • docs/topics/core-ir/test-plan.md
  • crates/edict-syntax/src/lib.rs
  • CHANGELOG.md
  • docs/topics/core-ir/canonical-encoding.md
  • docs/topics/obstruction-strands/README.md
  • docs/topics/obstruction-strands/test-plan.md
  • crates/edict-syntax/src/canonical.rs
  • crates/edict-syntax/src/core_ir.rs
  • docs/topics/compiler-spine/README.md
  • crates/edict-syntax/tests/compiler_spine.rs
  • crates/edict-cli/src/main.rs
  • docs/topics/compiler-spine/test-plan.md
  • crates/edict-syntax/src/compiler.rs
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/README.md
  • docs/topics/core-ir/README.md
  • docs/topics/syntax/test-plan.md
  • docs/topics/core-ir/test-plan.md
  • docs/topics/obstruction-strands/README.md
  • docs/topics/obstruction-strands/test-plan.md
  • docs/topics/compiler-spine/README.md
  • docs/topics/compiler-spine/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/README.md
  • docs/topics/core-ir/README.md
  • docs/topics/syntax/test-plan.md
  • docs/design/obstruction-strands-v0.md
  • docs/topics/core-ir/test-plan.md
  • docs/topics/core-ir/canonical-encoding.md
  • docs/topics/obstruction-strands/README.md
  • docs/topics/obstruction-strands/test-plan.md
  • docs/topics/compiler-spine/README.md
  • docs/topics/compiler-spine/test-plan.md
🔇 Additional comments (24)
crates/edict-cli/src/main.rs (1)

15-19: LGTM!

Also applies to: 1091-1091, 1238-1242, 1261-1284

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

411-416: LGTM!

CHANGELOG.md (1)

19-26: LGTM!

docs/design/obstruction-strands-v0.md (1)

165-180: LGTM!

Also applies to: 182-187

docs/topics/README.md (1)

60-62: LGTM!

docs/topics/compiler-spine/README.md (1)

41-44: LGTM!

Also applies to: 65-70, 85-85

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

106-109: LGTM!

fixtures/obstruction-strands/v0/stale-basis/README.md (1)

15-19: LGTM!

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

16-16: LGTM!

Also applies to: 47-48, 75-76, 93-94

docs/topics/core-ir/README.md (1)

48-52: LGTM!

Also applies to: 79-83

docs/topics/core-ir/canonical-encoding.md (1)

56-58: LGTM!

Also applies to: 91-99

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

16-17: LGTM!

Also applies to: 50-50, 94-94

docs/topics/obstruction-strands/README.md (1)

4-17: LGTM!

Also applies to: 51-65, 76-81

docs/topics/obstruction-strands/test-plan.md (1)

4-19: LGTM!

Also applies to: 33-42, 59-63, 76-76

crates/edict-syntax/tests/compiler_spine.rs (5)

10-13: LGTM!


89-111: LGTM!


126-138: LGTM!


600-630: LGTM!


734-743: LGTM!

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

222-249: LGTM!

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

120-122: LGTM!

docs/abi/edict-core.cddl (1)

239-265: LGTM!

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

756-766: LGTM!

Also applies to: 768-808, 835-847

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

743-747: LGTM!

Also applies to: 768-798

Comment thread crates/edict-syntax/src/compiler.rs Outdated
Comment thread crates/edict-syntax/tests/compiler_spine.rs
Comment thread crates/edict-syntax/tests/compiler_spine.rs

@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: 1b7e835498

ℹ️ 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-syntax/src/compiler.rs Outdated
Comment thread crates/edict-syntax/src/compiler.rs Outdated
@flyingrobots

Copy link
Copy Markdown
Owner Author

@codex please sanity-check this self-discovered audit item.

ID Severity File Lines Issue Planned mitigation
SELF-001 P5 crates/edict-syntax/src/compiler.rs 759-764 cargo xtask verify found clippy::semicolon_if_nothing_returned in the new Stmt::Require match arm. Add the explicit semicolon, rerun cargo xtask verify, and commit the lint fix without amending history.

@flyingrobots

Copy link
Copy Markdown
Owner Author

Activity Summary

ID Severity Source File Commit Outcome
1 P1 PR crates/edict-syntax/src/compiler.rs f0032da Preserved terminal obstruction payload fields named reason; added terminal_require_preserves_reason_payload_field.
2 P2 PR crates/edict-syntax/src/compiler.rs 9255c73 Rejected continue obstructed reason expressions rooted in local bindings; added continue_obstructed_reason_rejects_local_expression.
3 P5 PR crates/edict-syntax/tests/compiler_spine.rs 32ba34b Added self-defending fixture mutations with replace_required; fixed an existing no-op payload-order mutation.
4 P5 PR crates/edict-syntax/tests/compiler_spine.rs 9194753 Made assert_reason compare payload key sets order-independently; added regression coverage.
SELF-001 P5 Self crates/edict-syntax/src/compiler.rs a711a2e Fixed clippy::semicolon_if_nothing_returned found by cargo xtask verify.

Resolved review threads: PRRT_kwDOS96-Us6OYnII, PRRT_kwDOS96-Us6OYnIJ, PRRT_kwDOS96-Us6OYnIK, PRRT_kwDOS96-Us6OYnzj, PRRT_kwDOS96-Us6OYnzl.

Local evidence:

  • RED: cargo test -p edict-syntax --test compiler_spine terminal_require_preserves_reason_payload_field failed before f0032da.
  • RED: cargo test -p edict-syntax --test compiler_spine continue_obstructed_reason_rejects_local_expression failed before 9255c73.
  • RED: cargo test -p edict-syntax --test compiler_spine assert_reason_matches_payload_key_sets_without_order_sensitivity failed before 9194753.
  • GREEN: cargo test -p edict-syntax --test compiler_spine.
  • GREEN: cargo xtask verify.

Current gate note: remote CI and CodeRabbit restarted for head a711a2e and were pending when this summary was posted. @codex please review the final head if needed.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: a711a2e7c1

ℹ️ 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".

@flyingrobots

Copy link
Copy Markdown
Owner Author

Code Lawyer Re-Audit Summary

Current head: a711a2e.

Check Result Evidence
Dirty worktree lockdown Pass git status --porcelain returned empty.
Review threads Pass 5 total review threads, 0 unresolved active threads.
Diff self-audit Pass Re-reviewed git diff origin/main...HEAD; no new actionable findings.
Local gate Pass cargo xtask verify green on head a711a2e.
GitHub CI Pass stable, MSRV, and supply-chain checks are green.
CodeRabbit review Approved CodeRabbit submitted APPROVED at 2026-07-05T05:06:37Z.
CodeRabbit status context Failing Status says Prepaid credits exhausted — enable usage-based reviews despite the approval.

No new self-discovered code issues in this re-audit.

Merge judgment: code and CI are clean, but the strict automated check surface still contains the failing CodeRabbit status context. This appears to be an account-credit/status-context failure, not a code failure.

@flyingrobots
flyingrobots merged commit 4003d8d into main Jul 5, 2026
3 of 4 checks passed
@flyingrobots
flyingrobots deleted the core/obstruction-strand-ir branch July 5, 2026 05:46
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.

Lower obstruction continuations into Core

1 participant