Skip to content

feat(compiler): expose versioned OPY compile surface - #84

Merged
Teakowa merged 12 commits into
mainfrom
codex/issue-38-compile
Aug 29, 2026
Merged

feat(compiler): expose versioned OPY compile surface#84
Teakowa merged 12 commits into
mainfrom
codex/issue-38-compile

Conversation

@e54-bot

@e54-bot e54-bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • expose a versioned CompileReport from opy-compiler with compiler/catalog identity, stable status and failure classes, exact/normalized Workshop output, and source-attributed diagnostics
  • add opy-cli compile with deterministic text/JSON output, locale selection, and exit codes for success, compiler failure, and I/O/usage errors
  • add native compatibility corpus execution with complete project-input provenance, per-file hashes, and a canonical project digest
  • keep canonical-WIR comparison in the feature-gated internal opy-compat target; the public compiler API and opy-cli compile remain oracle-free
  • assign every compiler gap to a concrete opy-rs or workshop-rs issue, including workshop-rs#124 for canonical enum-domain ambiguity
  • connect the compiler compatibility gate to CI after Rust quality and preserve the independent source/frontend expectation contract
  • update the support matrix and OPY tooling documentation with the bounded Expose OPY compilation and close the end-to-end compatibility gate #38 surface and remaining gaps

Verification

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
  • cargo test -q --locked --workspace --all-targets --all-features
  • python3 -B -m unittest discover -s compatibility/tests (28 tests)
  • native compiler corpus through the compiler contract: 51 fixtures; 12 matches, 36 tracked known gaps, and 3 explicit unsupported cases
  • hosted CI run 33239736836: Rust stable/1.85, compiler compatibility, macOS, and Windows all passed

The compiler baseline requires independent evidence per fixture. Complete project-input, status, comparison-contract, and compatibility-evidence mismatches remain blocking; the native runner completed with no regression, divergence, or inconclusive result. The oracle snapshot verifier requires the pinned compatibility/oracle dependencies and is run in the dedicated oracle environment.

Fixes #38

@Teakowa Teakowa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Blocker

The new native corpus runner derives expected gaps from the implementation under test, so regressions can be downgraded to non-blocking results.

compatibility/run_native.py::compare() classifies every oracle-success/native-failure pair as known-gap and every oracle-failure/native-failure pair as expected-failure. fixture.json.expectedStatus is only copied into the report, and the existing independent compatibility/differential-expectations.json contract is not consulted. The runner then blocks only unexpected-success plus (by default) inconclusive, so a fixture that was independently expected to compile can regress to a native failure and still be reported as a non-blocking known-gap.

This bypasses the existing compatibility/diff.py safeguards: that runner validates independent native status/classification/evidence, turns expectation mismatches into unexpected-divergence/regression, compares failure diagnostics, and verifies that the producer input hash matches the pinned oracle input. run_native.py also omits that input-hash equality check, so a changed fixture can be compared against stale oracle evidence without a hard contract error.

That conflicts with #38's acceptance criteria that remaining failures be independently evidenced/tracked as concrete gaps and that the end-to-end report contain no hidden success cases. The compiler result being tested must not create its own expected baseline.

Please make the native path produce result records and reuse the existing differential expectation/comparison contract (or extract one shared comparator/expectation loader). Only an explicit durable expectation with evidence should be allowed to classify a case as known-gap/unsupported; mismatches must remain blocking unexpected-divergence/regression, and oracle/native input hashes should be required to match.

@e54-bot

e54-bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

Addressed in 2b5b883.

  • compatibility/run_native.py now only produces native result records and delegates expectation loading, input-hash validation, stage comparison, and classification to the existing compatibility/diff.py contract.
  • known-gap / unsupported can now only come from durable, evidence-backed differential-expectations.json entries.
  • expectation mismatches are blocking unexpected-divergence / regression; oracle/native input hashes are checked by the shared comparator.
  • updated compatibility/README.md to document the ownership and blocking behavior.

Validation: compatibility tests pass (21 tests). Running the native corpus through the shared comparator produces blocking results (26 regression, 10 unexpected-divergence, 8 inconclusive, 7 known-gap), so --allow-inconclusive does not bypass regressions.

@Teakowa Teakowa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Blocker

The previous runner-self-baselining issue is fixed, but the replacement still does not satisfy #38's end-to-end evidence contract: run_native.py now reuses differential-expectations.json/diff.py, yet those expectations describe the existing OPY source/frontend outcome contract rather than the new compiler outcome contract.

The PR's own current verification makes the mismatch observable: running the native compiler through the shared comparator reports 26 regressions, 10 unexpected divergences, 8 inconclusive cases, and only 7 declared known gaps. diff.run() correctly treats both regression and unexpected-divergence as blocking and returns non-zero, so this is not a passing end-to-end corpus baseline. --allow-inconclusive does not change that.

This matters beyond the exit code. Existing expectations intentionally encode source-level invariants such as “the native semantic model resolves this fixture” even when Workshop lowering is not part of that source contract. Reusing nativeStatus as the compiler expectation therefore turns legitimate, separately scoped lowering gaps into unexpected-divergence; conversely, changing those existing expectations to make the compiler green would weaken the already-established source regression contract. The two producer surfaces need independently evidenced expectations.

#38 requires the compatibility corpus to produce an end-to-end report with no hidden/inconclusive success cases, and requires every remaining failure outside the declared baseline to be independently evidenced and tracked as a concrete gap. A report containing 36 blocking regression/divergence results does not meet that acceptance criterion, and #8 cannot close from this evidence.

Please establish a compiler-specific durable expectation/baseline (or extend the expectation schema with a separate compiler outcome/classification) and run the native compiler against that contract. Do not overwrite the source/frontend expectations. Any compiler failure accepted as a gap must have independent evidence/provenance and a concrete owning follow-up; unexpected compiler regressions/divergences must remain blocking. The resulting #38 end-to-end run should pass for the declared baseline (with only explicitly accepted/tracked gaps, and inconclusive results handled according to the issue contract) before this PR is merged.

@e54-bot

e54-bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the second blocker in d356ddf.

The background/goal distinction is now explicit:

  • differential-expectations.json remains the source/frontend contract and was not changed.
  • New compiler-expectations.json is a separately reviewed compiler contract covering all 51 fixtures, with nativeStatus, comparison contract, evidence, owner, and note per fixture.
  • diff.py now has a compiler-specific comparator. It supports normalized-output, semantic-WIR evidence, and stable diagnostic-code contracts; status/hash mismatches remain blocking.
  • run_native.py runs against the compiler contract and now passes with 17 match, 31 known-gap, and 3 unsupported, with no regression, divergence, or inconclusive result.
  • Added tests for compiler expectation coverage, status mismatch blocking, and compiler input-hash validation.

The existing source/frontend expectation contract remains independent, so compiler lowering gaps are not downgraded into or promoted from source-level expectations.

@Teakowa Teakowa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Blocker

1. semantic-wir is currently a declared match, not an executed comparison

compare_compiler_fixture() checks the producer compile status, but the semantic-wir branch then unconditionally appends a semantic-wir: match stage and sets the fixture status to match; it does not compare any WIR/semantic value from the producer with pinned evidence. run_native.py only records the opy-cli compile --format json report, which contains Workshop text/diagnostics but no WIR semantic payload, and the runner does not execute or consume the referenced Rust test result.

That means a fixture can keep returning compile.status = success while its lowering semantics regress and the compiler corpus still reports it as a semantic-WIR match. Nine of the 17 declared compiler matches currently use this path, so more than half of the baseline is not actually checked by the machine-readable corpus gate.

This conflicts with #38's scope to compare the native compiler against pinned OverPy evidence using observable semantic/normalized contracts and with the acceptance criterion that the end-to-end report contain no hidden/inconclusive success cases.

Please make semantic-wir an executable comparison tied to the same fixture/input hash (for example, produce/consume a canonical WIR semantic representation or fingerprint and compare it with pinned evidence). If the referenced Rust tests are intentionally the independent evidence instead, the corpus runner must not fabricate a runtime semantic-wir: match; it needs a contract that actually verifies/consumes that evidence before counting the fixture as a corpus match.

2. The remaining gaps are still not tracked as concrete independently evidenced gaps

The separate compiler expectation file is the right boundary, but its non-match entries do not yet satisfy #38's tracking requirement. All 31 known-gap cases and all 3 unsupported cases point owner at aggregate parent opy-rs#8. #8 itself says the execution order ends with #38 → close #8, and #38 explicitly requires that #8 can close after the final gate. Therefore #8 cannot simultaneously be the durable owner for 34 remaining gaps after #38 closes.

Several of the new evidence entries are also only the fixture itself (for example the real-world parse/lexical failures) or a support-matrix:* entry. Those are useful repro/status references, but they are not independent evidence or concrete gap tracking; the support matrix is the declaration being justified. load_compiler_expectations() currently validates only that evidence and owner are non-empty strings, so these circular/self references are accepted as if they satisfied the policy.

Please reassess the failures as #38 requires and route each real failure mode to a concrete owning follow-up (multiple fixtures can share one issue; do not create one issue per fixture). Reuse existing follow-ups where they genuinely own the gap and route Workshop/WIR-owned deficiencies to workshop-rs. The expectation should reference durable regression/oracle/provenance evidence plus that concrete owner, rather than using #8/support-matrix as a catch-all.

Major

The compiler report advertises the wrong stage contract

run_compiler() calls the shared build_report(), but build_report() always declares the source-differential stages compile-status, diagnostics, exact-output, normalized-output, and semantic. Compiler results actually use compile-status plus normalized-output, semantic-wir, diagnostic-code, or compiler-contract depending on the expectation. The report's summary.byStage therefore describes one set of stages while the top-level comparison.stages advertises another.

Because #38 establishes this as a machine-readable end-to-end report, the metadata must describe the actual compiler comparison contract. Please parameterize the report metadata (or provide a compiler-specific report builder) so source and compiler reports each advertise the stages they really execute.

@e54-bot

e54-bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

Implemented review fixes in b6442dc: semantic-wir now compares native lowered WIR directly with the pinned oracle WIR and verifies both input hashes; reference parse failures remain inconclusive. The compiler baseline now requires concrete oracle/provenance evidence, uses owners opy-rs#88/#89 and workshop-rs#10/#123, and no longer uses parent #8. The compiler report advertises its actual stages, including compiler-contract. Local validation: cargo fmt --check, clippy -D warnings, workspace tests, 26 compatibility tests, and the 51-fixture native compiler gate all pass with 0 regression and 0 inconclusive results.

@Teakowa Teakowa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Blockers

1. The corpus input identity is still only the main-file hash, so multi-file oracle evidence can go stale without being rejected

The new semantic-WIR path correctly records and checks input hashes, but both sides still define the input as only fixture.json.source. run_native.py hashes source.read_bytes(), CompileReport::semanticWIR.inputSha256 hashes the same main source string, and load_compiler_expectations() validates the oracle by hashing only that one source path.

That is not a complete compilation input for multi-file fixtures. For example, synthetic/preprocessing/source.opy includes shared.opy, and that included file defines the Phase enum and double macro that materially determine the compiled result. oracle.json records only the main source.opy SHA. Changing shared.opy without refreshing the oracle therefore leaves every current input-hash check green even though the project being compiled is no longer the project that produced the pinned oracle.

#38 is establishing the final end-to-end evidence gate and explicitly relies on reproducible pinned evidence. The producer/oracle identity needs to cover the complete resolved source graph (or an equivalent deterministic project digest / per-file hash set), not only the entry file. The same project-wide identity should be present in the oracle and native result and compared before accepting status/output/WIR evidence.

2. Several remaining non-match entries still do not point to an issue that actually owns the declared gap

The new #88/#89 and workshop-rs#123 issues are the right direction, and most entries now have concrete oracle/provenance evidence. However the expectation-to-owner mapping is still incomplete:

  • real-world/overpy-pixelart, synthetic/declarations-rules, and synthetic/expressions-values are assigned to opy-rs#88, but #88 explicitly enumerates its tracked fixture scope and does not include those three cases.
  • real-world/overpy-cake and synthetic/chase-condition-agentlab are assigned to workshop-rs#10 with notes saying #10 owns canonical parser/domain disambiguation for Visible To / None. #10 is the Workshop conformance-corpus/seasonal-census parent; its scope does not own that parser/domain-disambiguation defect.

A non-empty owner string is not enough for #38's acceptance criterion that every remaining failure be independently evidenced and tracked as a concrete gap. Please either amend the relevant owning issues so their Goal/Scope/AC actually cover these failure modes, or point the expectations at/create the concrete existing Workshop/OPY issue that does. Do not use a broad corpus parent as the implementation owner for a parser semantic defect.

Major

1. Compatibility-only oracle machinery has leaked into the supported public compiler/CLI contract

To make the corpus executable, this patch adds CompileResult.semanticWIR, public Compiler::compile_source_report_with_semantic_reference(...), and user-visible opy-cli compile --semantic-reference. The CLI now knows how to deserialize a pinned oracle snapshot and inject it into the production compiler report. The documentation likewise presents this as part of the compile API.

This machinery exists to let compatibility/run_native.py inspect native WIR against test/oracle evidence; it is not part of ordinary OPY compilation. Making it a public versioned report field and user CLI flag turns compatibility-test plumbing into durable production API surface. That conflicts with the repository/testing boundary: tests and corpus verification should consume the production contract, not expand it with oracle-specific architecture.

Please keep the supported compile API/report focused on compilation. The compatibility harness can compare CompilationArtifact.wir with the pinned oracle through a dedicated internal compatibility binary/helper/test target (or another non-public support path) without making semantic-reference injection part of opy-cli compile or the public compile schema.

2. The new end-to-end gate is still manual-only; CI does not execute it

The current workflow runs the reusable Rust quality jobs and cross-platform opy-macro-js tests, but it never runs python3 -m unittest compatibility/tests or compatibility/run_native.py. The latest CI is therefore green without executing the machine-readable compiler corpus gate that this PR is intended to establish.

Once #38 closes, changes to lowering, compiler expectations, oracle handling, or the comparator can regress while ordinary PR CI remains green. This should be a durable compatibility/conformance gate after the cheap Rust correctness jobs: build the native CLI, run the compatibility unit tests, then run the native compiler corpus with the blocking comparator. Heavy compatibility work can depend on the existing Rust gate; it should not remain a manual verification step.

Minor

The PR verification summary is stale after the direct-WIR reclassification

The PR body still reports 51 fixtures; 17 matches, 31 tracked known gaps, and 3 explicit unsupported cases. The current compiler expectation file has 12 match, 36 known-gap, and 3 unsupported entries after the direct native-WIR comparison exposed the residual gaps. Update the PR verification text so the human status agrees with the current machine-readable baseline, as #38 requires.

The previous findings themselves are otherwise fixed: semantic-WIR is now executed against native lowered WIR, the compiler report advertises the correct stage contract, and the support matrix correctly downgraded the newly exposed lowering overclaims rather than hiding them.

Complete project input provenance, assign concrete gap owners, and keep canonical-WIR evidence in the internal compatibility target.

Fixes #38
@e54-bot

e54-bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

Review follow-up on commit 4b80ec7:\n\n- Completed project provenance: oracle and producer results now carry the full fixture .opy manifest, per-file SHA-256 values, and a canonical project digest; included-file changes are rejected by the comparator.\n- Gap ownership is concrete: opy-rs#88 now explicitly covers its compiler cases, and canonical Visible To / None ambiguity is owned by workshop-rs#124 rather than the broad #10 parent.\n- Removed CompileResult.semanticWIR, Compiler::compile_source_report_with_semantic_reference, and opy-cli compile --semantic-reference from the public surface. Direct WIR evidence is produced only by feature-gated internal opy-compat and stored under harness-level compatibility.semanticWIR.\n- Added the blocking Compiler compatibility gate CI job after Rust quality: builds both targets, runs 27 harness tests, runs all 51 native fixtures, and uploads the report.\n\nLocal result: 12 match / 36 known-gap / 3 unsupported, with no inconclusive or regression; Rust fmt, clippy, and locked all-target/all-feature tests pass. Full oracle execution was not run locally because the pinned oracle dependencies are not installed; snapshot identity validation is covered by the oracle-less harness tests.

Record the merged macro-lowering implementation as a normalized-output match.

Refs #85
Keep the issue-85 compile success while recording the remaining pinned-oracle WIR divergence as an owned known gap.

Refs #85
Record the public CLI and internal evidence target commands used by CI.
Keep semantic-WIR evidence rejected from the public compile result shape.
Expose the complete compatibility gate through workflow dispatch for explicit current-head verification.
# Conflicts:
#	crates/opy-compiler/Cargo.toml
Keep serde available after merging the macro-lowering implementation from main.
@e54-bot

e54-bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

Final hosted verification for head 2fa74b7:\n\n- CI run 33239736836 is green across Rust stable, Rust 1.85, macOS, Windows, and the new Compiler compatibility gate.\n- The compatibility gate built the public opy-cli and feature-gated opy-compat, ran the harness, and completed all 51 fixtures with 12 match / 36 known-gap / 3 unsupported; no inconclusive or regression result.\n- The branch was synchronized with latest origin/main so the branch-only gate includes the merged #85 macro-lowering implementation; the remaining preprocessing oracle WIR divergence stays explicitly owned by opy-rs#85.\n\nPR remains open with CHANGES_REQUESTED until the reviewer re-reviews the pushed fixes.

@Teakowa Teakowa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@Teakowa
Teakowa merged commit ec5fc17 into main Aug 29, 2026
10 checks passed
@Teakowa
Teakowa deleted the codex/issue-38-compile branch August 29, 2026 08:25
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.

Expose OPY compilation and close the end-to-end compatibility gate

2 participants