Skip to content

feat: P-022 step 3 — port own-cfg (AST → CFG lowering) with exact CFG-JSON parity#203

Merged
PhysShell merged 2 commits into
mainfrom
claude/own-net-issue-197-6ma9nk
Jul 10, 2026
Merged

feat: P-022 step 3 — port own-cfg (AST → CFG lowering) with exact CFG-JSON parity#203
PhysShell merged 2 commits into
mainfrom
claude/own-net-issue-197-6ma9nk

Conversation

@PhysShell

@PhysShell PhysShell commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Что и зачем

Третий шаг strangler-fig миграции P-022: новый крейт rust/crates/own-cfg понижает AST из own-syntax в CFG и проектирует канонический CFG-JSON seam, зеркаля ownlang/{cfg,cfg_json,buffers}.py строка-в-строку. Питон остаётся эталоном — поведение не меняется; расхождение считается багом Rust-стороны. Крейт зависит только от own-syntax (без рёбер на analysis/diagnostics, как требует DAG P-022).

Состав:

  • ir.rsKind/Symbol/Instr/Block/Cfg/Signature; идентичность символа выражена newtype-индексом арены (вместо id(sym)), блоки протянуты через BlockId, чтобы понижение никогда не алиасило &mut.
  • buffers.rsresolve/validate_policies/BufferInfo из buffers.py, значение-в-значение.
  • builder.rs — резолвер областей _Builder + понижение AST→CFG + collect_*.
  • json.rs — проекция cfg_json.py плюс сериализатор, воспроизводящий json.dumps(indent=2, sort_keys=True, ensure_ascii=True) байт-в-байт (на этом и держится байтовая идентичность seam).

Гейт паритета (по образцу syntax-фикстур шага 2): tests/test_cfg_fixtures.py (питон — эталон) прогоняет corpus/, examples/, tests/fixtures/ + курируемые кейсы и замораживает канонический CFG-JSON и диагностики (line, code) в tests/fixtures/cfg_parity.json; own-cfg/tests/parity.rs реплеит каждый кейс и требует байт-идентичный CFG-JSON, те же диагностики и — для отвергнутых источников — тот же текст ошибки парсера. 66 кейсов (60 корпус + 6 курируемых) зелёные; вывод Rust также сходится с python -m ownlang cfg --format json end-to-end.

Диагностики на этом шаге несут только code + line: CFG-JSON seam не содержит текста сообщений (это контракт verdict-слоя, закрепляемый позже SARIF-оракулом), поэтому человекочитаемый текст отложен до шага analysis/diagnostics — при этом поверхность данного шага полностью покрыта собственным оракулом. PR не трогает схему OwnIR, так что отложенный OwnIR-rename сюда не подмешивается.

Тип изменения

  • feat — новая возможность
  • fix — исправление бага
  • docs — документация
  • refactor / chore / test / ci — без изменения поведения

Как проверено

  • python tests/run_tests.py (включая новые test_cfg_fixtures.py, 66 кейсов в синхроне)
  • ruff check . и mypy — чисто
  • cd rust && cargo fmt --check && cargo clippy --all-targets && cargo test — 0 warnings, все тесты зелёные
  • python scripts/oracle_exact.py --selftest — PASS

Связанные issue

Closes #197

Чеклист

  • изменение покрыто тестом/селфтестом (полнокорпусный фикстур-паритет + юнит-тесты сериализатора и понижения)
  • README/docs обновлены при необходимости (не требуется — контракт seam документирован в docstring крейта; дизайн-док P-022 уже описывает слой)
  • коммиты в conventional-commit стиле (feat:)

🤖 Generated with Claude Code

https://claude.ai/code/session_01Cg6DVXahkyY68Ruu7f76rG


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added support for generating control-flow graphs and canonical JSON output for modules.
    • Expanded handling for buffers, ownership, branching, loops, calls, and return checks.
    • Added module-wide validation and detailed diagnostics for invalid configuration and flow issues.
  • Tests

    • Added parity tests to keep Rust output aligned with the reference implementation.
    • Added fixture generation and validation to ensure outputs remain byte-for-byte consistent.

…-JSON parity

Third strangler-fig step of the P-022 Rust core migration. `own-cfg` lowers the
`own-syntax` AST to a control-flow graph and projects the canonical CFG-JSON
seam, mirroring `ownlang/{cfg,cfg_json,buffers}.py` line-for-line. Python stays
authoritative; this port introduces no behaviour change.

Crate (rust/crates/own-cfg, depends on own-syntax only, per the P-022 DAG — no
analysis/diagnostics edge):
  * ir.rs      — Kind/Symbol/Instr/Block/Cfg/Signature; symbol identity is a
                 newtype arena index (replacing Python's id(sym)), blocks are
                 threaded by BlockId so lowering never aliases a &mut.
  * buffers.rs — buffers.py resolve/validate_policies/BufferInfo, value-for-value.
  * builder.rs — the _Builder scope resolver + AST→CFG lowering + collect_*.
  * json.rs    — cfg_json.py projection plus a serializer that reproduces
                 json.dumps(indent=2, sort_keys=True, ensure_ascii=True)
                 byte-for-byte (the property the seam rests on).

Parity gate (mirrors the step-2 syntax fixtures):
  * tests/test_cfg_fixtures.py (Python-authoritative) sweeps corpus/, examples/,
    tests/fixtures/ plus curated cases, and freezes each input's canonical CFG
    JSON + (line, code) diagnostics into tests/fixtures/cfg_parity.json; the
    Python suite fails if it is stale.
  * rust/crates/own-cfg/tests/parity.rs replays every case and asserts the
    byte-identical CFG JSON, the identical diagnostics, and — for rejected
    sources — the identical parser error text. 66 cases (60 corpus + 6 curated)
    green; the Rust output also matches `python -m ownlang cfg --format json`
    end-to-end.

Diagnostics carry code + line only at this step: the CFG-JSON seam does not
carry diagnostic message text (a verdict-layer contract pinned later by the
SARIF oracle), so the human message is deferred to the analysis/diagnostics
step, keeping this step's surface fully covered by its own oracle.

Closes #197

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cg6DVXahkyY68Ruu7f76rG
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a new own-cfg Rust crate that lowers own-syntax AST into a control-flow graph intermediate representation, mirroring the Python ownlang/cfg.py reference. It includes buffer storage policy resolution, CFG-JSON serialization matching CPython's exact output, and parity tests against corpus/example/curated fixtures shared with the Python implementation.

Changes

own-cfg crate: CFG lowering with Python parity

Layer / File(s) Summary
Crate scaffolding
rust/Cargo.toml, rust/crates/own-cfg/Cargo.toml
Adds own-cfg to the workspace members and defines its manifest with own-syntax and serde_json dependencies.
CFG IR types
rust/crates/own-cfg/src/ir.rs
Defines Kind, SymId/BlockId, Symbol, Instr, Block, Cfg, Signature, and the internal SymArena symbol arena.
Buffer policy resolution
rust/crates/own-cfg/src/buffers.rs
Defines BufferMode, BufferInfo, Policy/Policies, validate_policies, and resolve, applying mode-specific sizing/fallback rules and emitting diagnostics.
AST-to-CFG lowering builder
rust/crates/own-cfg/src/builder.rs
Implements build_cfg and per-statement lowering (Let, Call, AliasJoin, BorrowBlock, If, While, Return), including buffer-intent resolution and return-type validation.
Canonical CFG-JSON serialization
rust/crates/own-cfg/src/json.rs
Projects Cfg into a JSON Value with stable symbol indexing and implements python_dumps to replicate CPython's json.dumps(indent=2, sort_keys=True, ensure_ascii=True) output, with unit tests.
Crate entrypoint
rust/crates/own-cfg/src/lib.rs
Adds Diag, build_module, module_cfg_json, re-exports, and unit tests covering lowering, JSON versioning, and diagnostic ordering.
Parity test fixtures
rust/crates/own-cfg/tests/parity.rs, tests/test_cfg_fixtures.py
Adds Rust and Python tests that generate/verify a shared cfg_parity.json fixture, asserting byte-identical CFG JSON and diagnostics between the two implementations.

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

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant build_module
  participant Builder
  participant resolve
  participant canonical_json
  Caller->>build_module: build_module(module)
  build_module->>Builder: build_cfg(fn_decl, resources, signatures, policies, kinds)
  Builder->>resolve: resolve buffer intent options
  resolve-->>Builder: BufferInfo, diagnostics
  Builder-->>build_module: Cfg, diagnostics
  build_module-->>Caller: Vec<Cfg>, Vec<Diag>
  Caller->>canonical_json: canonical_json(cfgs)
  canonical_json-->>Caller: byte-canonical JSON string
Loading
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes implement the requested own-cfg port with exact parity tests and avoid introducing analysis/diagnostics dependencies.
Out of Scope Changes check ✅ Passed The diff stays focused on own-cfg, parity fixtures, and test harnesses with no obvious unrelated feature work.
Title check ✅ Passed The title clearly summarizes the main change: adding own-cfg AST→CFG lowering with exact CFG-JSON parity.
Description check ✅ Passed The description follows the template and fills all required sections with clear implementation, testing, issue, and checklist details.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/own-net-issue-197-6ma9nk

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: 9334faa4ad

ℹ️ 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 rust/crates/own-cfg/src/buffers.rs Outdated
// Python dict iterates in insertion order; a HashMap does not, so sort to
// keep the diagnostic stream stable.)
let mut names: Vec<&String> = policies.keys().collect();
names.sort();

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 Preserve policy diagnostic source order

When a caller validates multiple bad policy blocks whose names are not already sorted (for example policy Z before policy A), this sort emits the later A diagnostic before the earlier Z one. Python's authoritative validate_policies iterates policy declarations in insertion/source order, so the Rust port no longer matches the (line, code) diagnostic stream and users/fixtures see diagnostics out of source order; keep declaration order alongside the lookup map instead of sorting names.

Useful? React with 👍 / 👎.

…n order

Python's `validate_policies` iterates `policies.values()` in dict insertion
(source-declaration) order; the Rust port sorted policy names alphabetically for
HashMap determinism, which reorders the (line, code) diagnostic stream when
policy blocks aren't already alphabetized. Sort by declaration line instead —
that IS the source order — so the port matches Python. Add a unit test with
deliberately non-alphabetical policy names.

Not observable on the CFG-JSON seam (validate_policies is a `check`-pipeline
step, ported here for later use), but a divergence from Python all the same.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cg6DVXahkyY68Ruu7f76rG
@PhysShell
PhysShell merged commit a4df528 into main Jul 10, 2026
32 checks passed
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.

P-022 step 3: port own-cfg (AST → CFG lowering) to Rust with exact differential parity

2 participants