Skip to content

feat(obligations): obligation protocols — barrier-sensitive project invariants (P-025, first slice)#176

Merged
PhysShell merged 2 commits into
mainfrom
claude/own-net-typestate-analysis-q6k0k0
Jul 4, 2026
Merged

feat(obligations): obligation protocols — barrier-sensitive project invariants (P-025, first slice)#176
PhysShell merged 2 commits into
mainfrom
claude/own-net-typestate-analysis-q6k0k0

Conversation

@PhysShell

@PhysShell PhysShell commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Что и зачем

Новое sidecar-семейство анализов (паттерн di.py/effects.py): obligation-протоколы — проектные темпоральные инварианты вида «IsLoaded = false обязан стать true до OnPropertyChanged("Document") и до любого выхода из метода». opens создаёт обязательство, closes гасит, барьеры — сконфигурированные вызовы (с различающим аргументом и allow-списком) плюс по умолчанию return/throw/конец тела. Проверка path-sensitive: решётка-множество над {OPEN, CLOSED} с union на слияниях (definite/maybe-расщепление — прецедент OWN002 vs OWN009), локальный fixpoint для циклов с одноразовой эмиссией. Коды OBL001–004 + advisory OBL005 (мёртвый scope). Правила и события — аддитивные блоки OwnIR protocols[]/protocol_functions[] (без бампа версии, прецедент services/effects; словари fail-loud по IR4; сообщения line-free под фингерпринты OwnAudit). Killer demo: python -m ownlang ownir tests/fixtures/ownir/protocol_isloaded_violation.facts.json → OBL001 в BigDocumentViewModel.cs:241 с трейсом открыто@184 → барьер@241 → закрыто только@260 (в SARIF — codeFlows). Дизайн, границы и слайс эмиссии из Roslyn-экстрактора — в docs/proposals/P-025-obligation-protocols.md (экстрактор не тронут: CI-only, правится отдельным слайсом).

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

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

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

  • python tests/run_tests.py — зелёный, включая новые 70/70 obligation-проверок (tests/test_obligations.py)
  • ruff check . и mypy (strict) — чисто
  • CLI end-to-end: обе фикстуры через python -m ownlang ownir (нарушение → exit 1 + OBL001; чистый близнец → exit 0; OBL005-only → exit 0, warning); SARIF codeFlows проверен
  • состязательное ревью с репро-скриптами: подтверждённые находки исправлены (дубликаты имён протоколов — fail-loud в load() + first-wins на прямом пути; барьер, затенённый opens, отклоняется; схема↔парсер выровнены: protocolOpenClose со структурно обязательным value, null-семантика, minLength)

Связанные issue

Нет. Refs: docs/proposals/P-025-obligation-protocols.md (roadmap: эмиссия из экстрактора → межпроцедурные summaries на MOS/SCC → атрибуты/инференс правил → потребление в OwnAudit).

Чеклист

  • изменение покрыто тестом/селфтестом (70 проверок + 2 фикстуры + пины схемы в обе стороны)
  • README/docs обновлены при необходимости (spec/OwnIR.md §8, §Rules→§9, §Conformance→§10; spec/ownir.schema.json; P-025 + индексы proposals/ROADMAP; README не тронут сознательно — фича заезжает через spec+proposal, как DI/EFF)
  • коммиты в conventional-commit стиле

🤖 Generated with Claude Code

https://claude.ai/code/session_01NXzqX7Qwn5QzBLGVCATdgm


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added support for obligation protocol checks in OwnIR, including new findings for open/close/barrier rule violations and unmatched scoped rules.
    • Expanded the supported OwnIR format with protocol rules and method event traces for richer analysis.
  • Bug Fixes

    • Improved run summaries to report the actual advisory codes found instead of a fixed label.
    • Added clearer diagnostic messages and evidence for protocol-related findings.
  • Documentation

    • Updated the roadmap, proposal index, and OwnIR specification with the new obligation protocol workflow and status.

…nvariants (P-025, first slice)

A new sidecar analysis family (the di.py/effects.py pattern): project-declared
obligation protocols checked path-sensitively per method. An opening event
(IsLoaded = false) creates an obligation, a closing event discharges it, and it
must be closed before every declared barrier (OnPropertyChanged(Document)) and,
by default, every method exit (return / throw / end of body).

- ownlang/obligations.py: matchers, protocols, event trees (assign/call/return/
  throw/if/while), the {OPEN, CLOSED} set lattice with union joins (the
  definite/maybe split of OWN002 vs OWN009), local loop fixpoints with
  single-shot emission, open-site provenance, the opaque-write discharge
  asymmetry (may discharge, never invents), and explicit method scoping as the
  false-positive throttle.
- ownlang/ownir.py: additive OwnIR blocks protocols[]/protocol_functions[]
  (no version bump — the services/effects precedent; internal vocabularies are
  fail-loud per IR4, duplicate protocol names rejected at load),
  _protocol_findings beside _di_findings/_effect_findings, line-free messages
  (OwnAudit fingerprints on path|rule|message), evidence flow
  opened -> barrier -> late close (SARIF codeFlows).
- Codes OBL001-004 (barrier/exit x definite/maybe) + OBL005 (dead-scope
  advisory, never fails the build) in diagnostics.TITLES/EXPLANATIONS; the
  cmd_ownir summary now names the advisory codes present instead of
  hardcoding OWN050.
- spec/OwnIR.md §8 (Rules -> §9, Conformance -> §10) + ownir.schema.json
  $defs (protocol/protocolMatcher/protocolOpenClose/protocolEvent/
  protocolFunction), vocabularies pinned both ways by the tests.
- tests/test_obligations.py (70 checks) + killer-demo fixtures: OBL001 at
  BigDocumentViewModel.cs:241 (IsLoaded=false at 184, PropertyChanged(Document)
  at 241 on the warnings branch, closed only at 260), and its fixed twin
  staying silent.
- docs/proposals/P-025-obligation-protocols.md: decisions on the record, the
  Roslyn extractor emission slice (designed; extractor is CI-only), the
  MOS-based interprocedural phase, and non-goals.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NXzqX7Qwn5QzBLGVCATdgm
@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@PhysShell, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 45 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: de3eb5f3-473c-412b-a955-4fe7bdfe48c0

📥 Commits

Reviewing files that changed from the base of the PR and between 9e77980 and 3fbb33e.

📒 Files selected for processing (3)
  • docs/proposals/P-025-obligation-protocols.md
  • ownlang/__main__.py
  • ownlang/diagnostics.py
📝 Walkthrough

Walkthrough

Adds a new obligation-protocol analysis feature (P-025 "Own.Protocols") with a path-sensitive checker module, OwnIR schema/spec extensions for protocols/protocol_functions, bridge integration producing OBL001–OBL005 findings, diagnostics catalog entries, generalized advisory-code reporting in the CLI, fixtures, tests, and proposal documentation.

Changes

Obligation protocol analysis feature

Layer / File(s) Summary
Proposal documentation and roadmap entries
docs/proposals/P-025-obligation-protocols.md, docs/ROADMAP.md, docs/proposals/README.md
Adds the P-025 proposal describing the obligation model, precision policy, extractor plan, and roadmap, and links it from the roadmap and proposals index.
OwnIR schema and spec for protocols/protocol_functions
spec/ownir.schema.json, spec/OwnIR.md
Adds root-level protocols/protocol_functions schema definitions and a new spec section describing their vocabulary and load-time behavior, with section renumbering.
Obligation lattice, parsing, and path-sensitive walker
ownlang/obligations.py
New module implementing OPEN/CLOSED state, matcher/protocol/event dataclasses, parsers, a path-sensitive walker with loop fixpoint, check_protocols, and unmatched_scopes.
OwnIR bridge integration and diagnostics catalog
ownlang/ownir.py, ownlang/diagnostics.py, ownlang/__main__.py
Validates and runs obligation checks in load()/check_facts(), maps violations to OBL001–OBL005 Finding objects, registers diagnostic titles/explanations, and generalizes the advisory summary message beyond OWN050.
Fixtures and end-to-end obligation tests
tests/fixtures/ownir/protocol_isloaded_*.facts.json, tests/test_obligations.py
Adds clean/violation fixtures and a comprehensive test suite covering walker semantics, parsing rejection, bridge behavior, and schema/code binding.

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

Sequence Diagram(s)

sequenceDiagram
  participant Facts as OwnIR facts
  participant OwnIR as ownir.load/check_facts
  participant Obligations as obligations.check_protocols
  participant Walker as _Walker
  participant Diagnostics as diagnostics.TITLES

  Facts->>OwnIR: protocols[], protocol_functions[]
  OwnIR->>Obligations: parse_protocol/parse_method, check_protocols
  Obligations->>Walker: run(protocol, method)
  Walker-->>Obligations: Violation list
  Obligations-->>OwnIR: sorted Violations / unmatched_scopes
  OwnIR->>Diagnostics: map to OBL001-OBL005 codes
  Diagnostics-->>OwnIR: titles/explanations
  OwnIR-->>Facts: Finding objects (errors + advisory)
Loading

Possibly related PRs

  • PhysShell/Own.NET#8: Both PRs extend the ownlang/ownir.py load()/check_facts() pipeline with new fact bridges appended to the findings flow.
  • PhysShell/Own.NET#13: This PR's obligation findings coexist with the retrieved PR's OWN050/unresolved-subscription advisory handling in check_facts().
  • PhysShell/Own.NET#32: Both PRs modify check_facts()'s Finding aggregation logic, where obligation findings would pass through the same dedup path.
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding obligation protocols as a new sidecar analysis slice.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/own-net-typestate-analysis-q6k0k0

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.

Copy link
Copy Markdown
Owner Author

Живое демо слайса (обе фикстуры лежат в tests/fixtures/ownir/):

$ python -m ownlang ownir tests/fixtures/ownir/protocol_isloaded_violation.facts.json
BigDocumentViewModel.cs:241: error: [OBL001] obligation 'DocumentLoading' is still open
  when barrier 'OnPropertyChanged(Document)' fires in
  'Broker.BigDocumentViewModel.LoadBigDocument' — 'IsLoaded = true' must happen first
  [resource: protocol obligation]

1 finding.   # exit 1

Тот же finding в SARIF несёт кликабельный codeFlows:

step: 184 — obligation 'DocumentLoading' opens here (IsLoaded = false)
step: 241 — barrier 'OnPropertyChanged(Document)' fires while it is open
step: 260 — closed here — after the barrier has already fired

Чистый близнец (protocol_isloaded_clean.facts.json, флаг восстановлен до уведомления) — молчит, exit 0. Разрешённые уведомления (OnPropertyChanged(IsBusy/Progress)) внутри открытого обязательства не считаются барьером — allow-список.

Правило целиком — данные, не код (фрагмент из фикстуры):

{"name": "DocumentLoading",
 "opens":  {"kind": "assign", "target": "IsLoaded", "value": false},
 "closes": {"kind": "assign", "target": "IsLoaded", "value": true},
 "barriers": [{"kind": "call", "callee": "OnPropertyChanged",
               "args": ["Document", "Rows", "Totals", "SelectedItem"]}],
 "allow":    [{"kind": "call", "callee": "OnPropertyChanged",
               "args": ["IsLoaded", "IsBusy", "Progress", "StatusText"]}],
 "scope": {"methods": ["BigDocumentViewModel.LoadBigDocument"]}}

Следующие слайсы по P-025: эмиссия событий из OwnSharp.Extractor (якоря расписаны в proposal — LowerFlowStmt + continuation-threading даёт корректные exceptional-пути бесплатно), затем межпроцедурные obligation-summaries на MOS/SCC-канале ownership.py.


Generated by Claude Code

@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 `@docs/proposals/P-025-obligation-protocols.md`:
- Around line 26-33: The fenced examples in the proposal document are missing
language tags, which will trigger markdownlint MD040. Update the unlabeled code
fences in the relevant sample blocks, using csharp for the C# snippet and text
(or a list-style fence) for the protocol-verbs example. Check the surrounding
proposal sections so both affected fenced blocks are labeled consistently.

In `@ownlang/__main__.py`:
- Around line 351-359: The advisory summary has been generalized beyond OWN050,
but nearby documentation still refers to OWN050-only behavior. Update the
`cmd_ownir` docstring and the comment block above the summary logic in
`ownlang.__main__` so they describe advisory notes generically and mention both
OWN050 and OBL005 where appropriate, keeping the wording aligned with the
existing `summary`/`note_codes` behavior.

In `@ownlang/diagnostics.py`:
- Around line 190-214: Add missing EXPLANATIONS entries for OBL002 and OBL004 in
diagnostics.py so they have the same fix guidance as OBL001 and OBL003. Mirror
the existing OBL001/OBL003 wording style and keep the descriptions aligned with
the corresponding “maybe” versions emitted by _OBL_CODE in ownlang/ownir.py.
Ensure the new entries are discoverable by ownlang explain for OBL002 and
OBL004, not just the title.
🪄 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: 9e81d411-ac48-4f1d-9625-23cfcf64e138

📥 Commits

Reviewing files that changed from the base of the PR and between db6f673 and 9e77980.

📒 Files selected for processing (12)
  • docs/ROADMAP.md
  • docs/proposals/P-025-obligation-protocols.md
  • docs/proposals/README.md
  • ownlang/__main__.py
  • ownlang/diagnostics.py
  • ownlang/obligations.py
  • ownlang/ownir.py
  • spec/OwnIR.md
  • spec/ownir.schema.json
  • tests/fixtures/ownir/protocol_isloaded_clean.facts.json
  • tests/fixtures/ownir/protocol_isloaded_violation.facts.json
  • tests/test_obligations.py

Comment on lines +26 to +33
```csharp
IsLoaded = false; // the document tree is now inconsistent — on purpose
RebuildIndexes();
if (hasWarnings)
OnPropertyChanged(nameof(Document)); // ← published the broken object
IsLoaded = true;
OnPropertyChanged(nameof(Document)); // this one is fine
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add language tags to the fenced examples.

Both fenced blocks are unlabeled, which will trip markdownlint MD040. Use csharp for the sample and text (or a list) for the protocol-verbs block.

Also applies to: 50-55

🤖 Prompt for 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.

In `@docs/proposals/P-025-obligation-protocols.md` around lines 26 - 33, The
fenced examples in the proposal document are missing language tags, which will
trigger markdownlint MD040. Update the unlabeled code fences in the relevant
sample blocks, using csharp for the C# snippet and text (or a list-style fence)
for the protocol-verbs example. Check the surrounding proposal sections so both
affected fenced blocks are labeled consistently.

Source: Linters/SAST tools

Comment thread ownlang/__main__.py
Comment thread ownlang/diagnostics.py
- P-025: tag the protocol-verbs fence as text (MD040; the C# fence was
  already tagged)
- __main__: de-OWN050-ify the cmd_ownir docstring and the advisory comment
  block — the band now carries OBL005 too
- diagnostics: EXPLANATIONS for the maybe-siblings OBL002/OBL004, mirroring
  OBL001/OBL003 so ownlang explain answers all four symmetrically

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NXzqX7Qwn5QzBLGVCATdgm
@PhysShell
PhysShell merged commit 5ea68da into main Jul 4, 2026
31 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.

2 participants