Skip to content

feat(native): report macro errors natively without re-running Python - #1051

Merged
kvlonge merged 4 commits into
mainfrom
feat/native-macro-errors
Oct 9, 2026
Merged

kvlonge merged 4 commits into
mainfrom
feat/native-macro-errors

Conversation

@kvlonge

@kvlonge kvlonge commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Why

With native rendering as the default, a failing compile re-ran the whole render stage in Python only to report its error. Every macro ran twice, side effects included.

Changes

  • run_with_macro_bridge runs the stage once and raises its first error directly. Every error in that stage is raised by the same Python code over the same inputs, in the same order: macro execution errors (with the macro's exception as the cause), non-string returns, unparsable arguments, unknown, private and inaccessible macros, and load-time call cycles. Only memo/store replay of successful calls differs, which the macro determinism contract covers.
  • Bridge invariant checks (scan end, replay events) stay explicit NativeStageMismatchErrors and are covered by the expansion differential.
  • Text the native scan, memo or splice cannot encode (lone surrogates from env vars, --vars or macro output) now falls back to Python instead of raising UnicodeEncodeError. A call whose store key cannot be built (encoding or recursion failure) is treated as uncacheable: it runs normally and is not stored.
  • bridge_independent no longer changes behaviour. Parity tests still use it to count natively produced exact errors.
  • Engine-count E2E tests now expect one macro run per engine. New SQL-test attachment cases use the renamed expected_native_entries field.

Verification

  • A generated-project parity test (150 seeded projects, over 10 error kinds) shows identical errors and identical macro execution logs on python, native and native-preview. It fails against the old re-run.
  • An E2E test on all three engines covers identical reports, single macro execution and lifecycle error_type. New failure-corpus cases are included, plus a CLI test for a surrogate --vars value with the store attached.
  • cargo test, clippy/fmt on 1.99.0, both compiler differentials, the differential E2E suite, make check-ci, make test and the hygiene scan pass.

@kvlonge
kvlonge enabled auto-merge (squash) October 9, 2026 00:37
@kvlonge
kvlonge merged commit 0ce6787 into main Oct 9, 2026
39 checks passed
@kvlonge
kvlonge deleted the feat/native-macro-errors branch October 9, 2026 01:48
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.

1 participant