feat(ownir): OwnIR contract hardening — spec, fail-loud guards, version single-sourcing#172
Conversation
|
Warning Review limit reached
Next review available in: 46 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (10)
📝 WalkthroughWalkthroughThis PR adds a formal OwnIR specification document, enforces fail-loud behavior for unknown flow ops and unregistered diagnostic codes, replaces an assert with an explicit raise in a flow-join invariant, refactors the test runner to auto-discover tests, and updates related documentation and comments. ChangesOwnIR contract formalization and fail-loud enforcement
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Frontend as Frontend Producer
participant OwnIR as ownlang/ownir.py
participant Diagnostics as ownlang/diagnostics.py
participant Tests as tests/test_ownir.py
Frontend->>OwnIR: submit facts payload (with flow op)
alt op is unknown
OwnIR-->>Frontend: raise OwnIRError (version skew)
else op is known
OwnIR->>OwnIR: lower flow op
end
OwnIR->>Diagnostics: construct Diagnostic(code)
alt code not in TITLES
Diagnostics-->>OwnIR: raise ValueError
else code registered
Diagnostics-->>OwnIR: title resolved
end
Tests->>OwnIR: check_facts(unknown op payload)
OwnIR-->>Tests: OwnIRError raised
Tests->>Frontend: regex-extract ownir_version
Tests->>OwnIR: compare to OWNIR_VERSION
Possibly related PRs
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Track A (contract hardening), first tickets from the tech-debt register. - _lower_flow no longer has an else-less if/elif chain: an unknown flow op now raises OwnIRError instead of being silently dropped. Silently skipping a new compound op would drop the acquire/release facts nested inside it — fabricating a leak (a lost release) or hiding one (a lost acquire) while every existing fixture still passes. A new op is a vocabulary change and must bump OWNIR_VERSION. Pinned by a new test_ownir check (209/209). - spec/OwnIR.md: the OwnIR contract was only prose in a module docstring; it is now a normative spec — envelope, the versioning + evolution policy (what does and does not bump OWNIR_VERSION), the resource-kind and flow-op vocabularies, the DI graph, and rules IR1–IR6 with a conformance section tying each to tests/test_ownir.py. Registered in spec/README.md. Refs docs/notes/tech-debt-register.md (N1, N4). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FJSfUpRbRXegrwJNV1rx1X
…c code Track A (contract hardening), continued. - analysis.join(): the block-scoped-loan invariant was a bare `assert`, stripped by `python -O` (a silently-wrong merge if block-scoping is ever relaxed). Now an explicit `if … raise AssertionError`, mirroring _join_handle_rid. (N9) - Diagnostic now validates its code at construction: a code absent from TITLES raises ValueError instead of silently rendering an empty title. The full suite confirms every emitted code is registered; `title` indexes instead of `.get(..., "")`. Closes the one stringly-typed contract's silent-"" hole cheaply (a full StrEnum is the heavier follow-up). Pinned by test_diagnostics. (N6) - Register: mark N1/N4/N6/N9 done; re-scope N8 — a dedicated syntax-error code is NOT surgical (OWN020 is the suite-wide parse/lex-rejection code, entangled with the lexer's rejected-keyword mechanism and ~6 test helpers). Refs docs/notes/tech-debt-register.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FJSfUpRbRXegrwJNV1rx1X
…t or-chain) Track A (N2). The suite aggregator imported ~16 test modules by hand and gated on a 25-term `or` of their return codes; adding a module meant remembering to thread its rc through that chain, and a forgotten term silently dropped a whole module from the gate. The runner now globs `test_*.py`, calls each module's `run()`, and returns `any(rc)` (plus the inline analysis/codegen flags). A new test file is picked up with no edit here; a module missing `run()` fails the suite loudly; discovering zero modules fails loud. `test_codegen_props` keeps its lighter in-suite iteration count (3000) via a one-entry special-case map. Per-module output is unchanged (now ordered by filename). Refs docs/notes/tech-debt-register.md (N2). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FJSfUpRbRXegrwJNV1rx1X
… rationale Track A (N4, no-dependency slice). - test_ownir now asserts each frontend producer (Program.cs, ownts.py) stamps the same ownir_version as the core's OWNIR_VERSION — so 'bumped the core, forgot a frontend' (or the reverse) fails loudly instead of silently mis-reading facts. This is the no-dep half of version single-sourcing; the P-022 own-ir crate will be a fourth producer to fold in (or generate from the schema). (211/211 bridge checks.) - Register: recover and record the strong pro-schema argument now that its trigger has fired. OwnIR is THE language every frontend + the core speak; a language without a formal grammar lies about itself. The schema looked redundant only while load() was the sole validator (zero-dep, no second type set). #170's crates/own-ir hand-writes Rust serde structs that must match load() — two hand-maintained validators in two languages, the exact drift formalization exists to kill. So the schema flips from a shadow of load() to the source both are generated from (serde via typify; C#/TS source-gen), collapsing the hand-synced shapes AND the four ownir_version literals into one authority. Recommendation: co-design spec/ownir.schema.json WITH the own-ir crate, not a jsonschema validator bolted onto the zero-dep core. Refs docs/notes/tech-debt-register.md (N4), P-022 #170. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FJSfUpRbRXegrwJNV1rx1X
…lationship Track A (N10). The extractor's IsOwningFactory and the bridge's _BCL_FRESH_BY_NS both carried 'kept in lockstep' comments, but the lists had already diverged (the extractor knows ADO.NET ExecuteReader/CreateCommand/BeginTransaction and network Accept*; the bridge table lists neither) — the comments lied. They are not a mirror and should not be: IsOwningFactory is the emission authority (a match emits an 'acquire' fact), so it is the superset; the bridge table is consulted only for 'call'-op results (_callee_returns_fresh), and since owning factories are emitted as 'acquire' not 'call', it is a deliberate subset — the C#-only entries never arrive as calls, so adding them would be dead weight. Both comments now state the real roles, the safety invariant (owning factory ⇒ acquire), and the generate-both-from-schema exit. No behaviour change. Refs docs/notes/tech-debt-register.md (N10). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FJSfUpRbRXegrwJNV1rx1X
74bf790 to
6aad152
Compare
|
Перебазировал на свежий Связка с P-022 #170 (для ревьюеров): этот PR — контрактная пара к Rust-фундаменту.
Merge-порядок с #170 не важен — файлы не пересекаются (кроме Generated by Claude Code |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@spec/OwnIR.md`:
- Around line 49-54: The OwnIR versioning guidance for resource kinds is too
permissive: new discriminator values in the resource routing logic can change
analysis behavior and should not be treated as harmless additive metadata.
Update the policy in spec/OwnIR.md around the resource-kind rules and §4 routing
so that changes to resource-kind values either require bumping OWNIR_VERSION or
explicitly fail on unknown values instead of silently defaulting to
subscription; reference the resource-kind discriminator and OWNIR_VERSION
guidance when revising the table and surrounding text.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 81a426f6-cc32-456b-822e-24168f6ef64d
📒 Files selected for processing (10)
docs/notes/tech-debt-register.mdfrontend/roslyn/OwnSharp.Extractor/Program.csownlang/analysis.pyownlang/diagnostics.pyownlang/ownir.pyspec/OwnIR.mdspec/README.mdtests/run_tests.pytests/test_diagnostics.pytests/test_ownir.py
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 74bf79068d
ℹ️ 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".
| "components": [ /* §4 owned-resource records, grouped by type */ ], | ||
| "functions": [ /* §5 flow bodies (intra-procedural CFG facts) */ ], | ||
| "services": [ /* §6 DI registration graph */ ] |
There was a problem hiding this comment.
Include effects in the OwnIR contract
When the OwnTS frontend emits effects (frontend/ownts/ownts.py:598-602) and the core validates/consumes it (ownlang/ownir.py:548-577), this new normative envelope leaves that top-level block out. If the promised schema/types are generated from this spec, valid EFF001 fact sets would either lose the effect graph or be rejected, disabling effect-storm diagnostics. Please document effects as an optional top-level block and specify its shape alongside the other consumed OwnIR sections.
Useful? React with 👍 / 👎.
Review follow-ups on PR #172. - CodeRabbit (Major): a present-but-unknown resource kind fell through §4 routing to the owned/subscription path and mis-classified — the same silent-misroute N1 fixes for flow ops. load() now rejects a present-but-unknown against the known-kinds set (_KNOWN_RESOURCE_KINDS); an ABSENT field still defaults to (additive). So a new kind is a vocabulary change that must bump OWNIR_VERSION — spec/OwnIR.md §2 table + IR3/IR4 updated accordingly, docstring corrected (field-vs-value). Pinned by two test_ownir checks (unknown kind raises; absent defaults). 213/213. - Codex (P2): the top-level block (OwnTS emits it, effects.py consumes it → EFF001) was missing from the spec envelope — generating types from the spec would drop/reject effect facts. Added to §1 and a new §7 documenting its shape (io/line/deps/bindings); §8/§9 renumbered; conformance updated. - Register §2: correct the now-inaccurate 'unknown kinds coerce to subscription' note to the closed-enum-for-present-values reality. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FJSfUpRbRXegrwJNV1rx1X
Review follow-ups on PR #172. - CodeRabbit (Major): a present-but-unknown resource kind fell through the §4 routing to the owned/subscription path and was mis-classified -- the same silent-misroute that N1 fixes for flow ops. load() now rejects a present-but-unknown "resource" against the known-kinds set (_KNOWN_RESOURCE_KINDS); an ABSENT field still defaults to "subscription" (additive). So a new kind is a vocabulary change that must bump OWNIR_VERSION -- spec/OwnIR.md section 2 table + IR3/IR4 updated, docstring corrected (field-vs-value). Pinned by two test_ownir checks (unknown kind raises; absent defaults). 213/213. - Codex (P2): the top-level "effects" block (OwnTS emits it, effects.py consumes it -> EFF001) was missing from the spec envelope -- generating types from the spec would drop/reject effect facts. Added to section 1 and a new section 7 documenting its shape (io/line/deps/bindings); Rules/Conformance renumbered; conformance updated. - Register section 2: correct the now-inaccurate "unknown kinds coerce to subscription" note to the closed-enum-for-present-values reality. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FJSfUpRbRXegrwJNV1rx1X
723e9c7 to
fc9b7a2
Compare
Что и зачем
Закаляет контракт OwnIR — несущий шов «фронтенды продуцируют/потребляют факты, ядро выносит вердикт» — по «Now»-корзине tech-debt-реестра. Даёт формальную грамматику (
spec/OwnIR.md), закрывает молчаливые дыры (проглатывание неизвестных фактов, тихий""на опечатке кода,assert, срезаемый-O) и делает гейтинг тестов и версию продюсеров не-забываемыми. Пара к P-022 #170:spec/OwnIR.md— проза-грамматика контракта, который реализует крейтown-ir.Тип изменения
Как проверено
python tests/run_tests.py— зелёный (авто-дискавери модулей; test_ownir 211/211; test_diagnostics +code-validation)ruff check .иmypy— чисто (18 файлов)python scripts/<...>.py --selftest)Что внутри (по тикетам реестра):
_lower_flowбольше не имеетif/elifбезelse: неизвестный flow-op →OwnIRError, а не молчаливое проглатывание вложенных acquire/release. Пинается тестом.spec/OwnIR.md(envelope, словари resource-kind + flow-op, DI-граф, политика эволюции версии IR1–IR6), зарегистрирована вspec/README.md; плюс version single-sourcing — тест грепитProgram.cs/ownts.pyи требует равенстваownir_versionядру. Schema (spec/ownir.schema.json) намеренно отложена: её триггер сработал в feat: P-022 first deliverable — CFG JSON seam, Rust workspace + own-ir, exact oracle #170 (крейтown-ir= второй языко-нативный набор типов), и правильно со-проектировать её с этим крейтом и генерить Rust-типы из неё, а не вешатьjsonschemaна zero-dep ядро — обоснование в реестре.Diagnosticотвергает код без записи вTITLESпри конструировании (весь сьют подтвердил, что все эмитируемые коды зарегистрированы);titleиндексирует вместо.get(...,"").assertинварианта займов вjoin()→ явныйraise(не срезаетсяpython -O), по образцу_join_handle_rid.test_*.pyи гейтит наany(rc): новый тест-файл включается сам, модуль безrun()валит сьют — убит хрупкий 25-членныйor.IsOwningFactoryзнает ADO.NET/network,_BCL_FRESH_BY_NS— нет) заменены на точное описание ролей (эмиссия-авторитет-суперсет vs call-op-фолбэк-субсет) + инвариант безопасности; поведение не менялось.Связанные issue
Нет issue. Refs P-022 (#166, #168, #170). Реализует «Now»-корзину
docs/notes/tech-debt-register.md.Чеклист
spec/OwnIR.md,spec/README.md, реестр обновленыfeat:,fix:,test:,docs:)🤖 Generated with Claude Code
https://claude.ai/code/session_01FJSfUpRbRXegrwJNV1rx1X
Generated by Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Tests
Documentation