Skip to content

feat: interprocedural stage 2 — per-overload signature keys (sig) in the MOS#217

Merged
PhysShell merged 3 commits into
mainfrom
claude/plans-tasks-review-u77dfs
Jul 11, 2026
Merged

feat: interprocedural stage 2 — per-overload signature keys (sig) in the MOS#217
PhysShell merged 3 commits into
mainfrom
claude/plans-tasks-review-u77dfs

Conversation

@PhysShell

@PhysShell PhysShell commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Что и зачем

Этап 2 межпроцедурной карты (roadmap §5 / tz §6.1): перегрузки больше не сливаются в одно консервативное summary. Опциональное поле sig (канонический список типов параметров) на functions[]-записи и call-опе даёт каждой перегрузке собственный ключ name(sig) РЯДОМ со слитым по имени fallback'ом; все потребители резолвятся через единый _mos_lookup (sig-ключ → точное имя → каноническое). Возвращает recall, который merge терял: sig-вызов fresh-перегрузки смешанной фабрики → OWN001 на брошенном результате, sig-вызов/forward в consume-перегрузку → OWN002; borrow-перегрузка → проверенный lend без OWN051-шума. Fallback несущий: нет/не совпал sig с любой стороны ребра → слитое summary (сегодняшнее поведение), никогда «мимо»; first_party/overloaded остаются на голом имени (INV4). Аддитивно, без бампа OWNIR_VERSION; solver не тронут (ключи для него непрозрачны). Extractor штампует sig из одного IMethodSymbol на обеих сторонах ребра (generic-аргументы стёрты до backtick-арности — коллизия просто сливает, никогда не мис-резолвит). Попутно починен скрытый недетерминизм паритетного дампа (имя параметра слитой перегрузки зависело от порядка входа).

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

  • feat — новая возможность

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

  • python tests/run_tests.py — 270/270 bridge-проверок (14 новых по матрице ТЗ §6.1: раздельные контракты, fallback без/с несовпавшим sig, global::-qualified sig, смешанные продюсеры, fresh-регресс fallback'а, дубликат name+sig, байт-детерминизм sig-дампа)
  • ruff check . и mypy
  • e2e-якорь: frontend/roslyn/samples/OverloadSigSample.cs + ассерты в wpf-extractor job (sig на обеих сторонах ребра в фактах; OWN001 в Drop) — extractor-половина проверяется CI (локально dotnet нет)

Связанные issue

Closes #216. Refs: roadmap docs/notes/interprocedural-roadmap.md §5, ТЗ docs/notes/interprocedural-tz.md §6.1.

Чеклист

  • изменение покрыто тестом/селфтестом (или объяснено, почему нет)
  • README/docs обновлены при необходимости (spec/OwnIR.md §5.1, schema, статус-заметки в roadmap/ТЗ)
  • коммиты в conventional-commit стиле (feat:, fix:, docs: …)

🤖 Generated with Claude Code

https://claude.ai/code/session_01LsWw4Ay8KLTHFom1HvRu3U


Generated by Claude Code

Summary by CodeRabbit

  • New Features
    • Added overload-signature (sig) support to interprocedural stage 2 resolution, enabling contracts and call outcomes to match the correct overload.
    • Propagated sig through flow calls and tracked factory/return/forwarding behavior for more precise ownership conclusions.
    • Added an OverloadSigSample demonstrating overload-specific leak attribution.
  • Bug Fixes
    • Improved overload matching accuracy and subscription-leak reporting.
  • Documentation
    • Updated OwnIR spec, schema, and roadmap to document sig format, fallback rules, and validation behavior.
  • Tests
    • Added stage-2 test coverage for matching, fallback behavior, global-qualified calls, mixed facts, and deterministic summary output.

Same-name overloads no longer have to share one conservative summary. A
functions[] record and a call op may both carry an optional 'sig' — the
canonical parameter-type list (FQ names, comma-separated, no spaces,
generic arity via backtick, global:: stripped). When an overloaded name's
records carry it, _build_skeletons emits one summary per overload keyed
name(sig) BESIDE the name-merged fallback, and every consumer resolves
through one helper (_mos_lookup: sig key -> exact name -> canonical name):
the overload channel, kill sites, OWN051 collection, the fresh-result
mint, branch hoisting and the method's own param seeding — so the untrack
set, the advisories and the emitted effects can never disagree.

The fallback rule is load-bearing (tz §6.1): a sig missing or unmatched on
either side of an edge lands on the merged summary — degraded, never a
wrong overload — and the first_party/overloaded suppressions stay keyed on
the bare name (INV4). Additive per the IR evolution policy: no
OWNIR_VERSION bump; a non-string sig on a record fails load, on a flow op
it reads as absent.

Extractor: sig is stamped from the same resolved IMethodSymbol on both
sides of the edge (CanonicalSig/CanonicalTypeName; type arguments erased
to backtick arity — a collision merely merges, never mis-resolves), on the
main flow record and the first-party-factory call op.

Also fixes a latent parity-dump nondeterminism the new matrix exposed:
_merge_skeletons took the first-seen param name per index, which depended
on functions[] input order; it now takes the lexicographic min.

Recall restored (e2e anchor OverloadSigSample.cs + CI assertions): a
sig'd call to the fresh overload of a mixed factory leaks its dropped
result (OWN001); a sig'd forward to a consume overload yields OWN002 —
both were silenced by the merge. Test matrix from tz §6.1 lands in
tests/test_ownir.py (14 new checks); solver untouched (keys stay opaque).

Tier B review (DoD): Process.Start / new StreamReader(stream) stay
excluded — their ambiguity is BCL-side (static-vs-instance, adopt); a
sig-keyed Tier B table is now possible and recorded as follow-up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LsWw4Ay8KLTHFom1HvRu3U
Comment thread frontend/roslyn/samples/OverloadSigSample.cs Fixed
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 051d4abe-8c2d-4ee6-a604-37623e1e875e

📥 Commits

Reviewing files that changed from the base of the PR and between 540e07d and d82d7ef.

📒 Files selected for processing (5)
  • .github/workflows/ci.yml
  • frontend/roslyn/OwnSharp.Extractor/Program.cs
  • frontend/roslyn/samples/OverloadSigSample.cs
  • ownlang/ownir.py
  • tests/test_ownir.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • .github/workflows/ci.yml
  • frontend/roslyn/OwnSharp.Extractor/Program.cs
  • tests/test_ownir.py
  • ownlang/ownir.py

📝 Walkthrough

Walkthrough

Stage 2 interprocedural ownership analysis now supports canonical per-overload sig keys across Roslyn extraction, OwnIR summary resolution, forwarding, freshness analysis, specifications, tests, and CI verification.

Changes

Interprocedural overload signatures

Layer / File(s) Summary
Contracts and signature fact emission
spec/OwnIR.md, spec/ownir.schema.json, frontend/roslyn/OwnSharp.Extractor/Program.cs, frontend/roslyn/samples/OverloadSigSample.cs
OwnIR defines optional sig fields, while the extractor emits canonical overload signatures for function records and factory calls.
MOS lookup and overload skeletons
ownlang/ownir.py
The bridge validates signatures, resolves exact name(sig) summaries with merged-name fallback, and builds overload-specific skeletons for forwarding and returns.
Overload-aware ownership inference
ownlang/ownir.py
Call routing, transfer checks, kill sites, freshness decisions, parameter contracts, and return propagation use signature-resolved summaries.
Validation and regression coverage
tests/test_ownir.py, .github/workflows/ci.yml, docs/notes/*, ownlang/ownership.py
Tests cover exact and fallback resolution, forwarding, factories, determinism, and invalid input; CI verifies extracted signatures and the expected leak finding.

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

Sequence Diagram(s)

sequenceDiagram
  participant CSharpExtractor
  participant OwnIRFacts
  participant OwnIRBridge
  participant MOS
  participant CI
  CSharpExtractor->>OwnIRFacts: Emit functions[].sig and call.sig
  OwnIRFacts->>OwnIRBridge: Load validated facts
  OwnIRBridge->>MOS: Resolve name(sig)
  MOS-->>OwnIRBridge: Return overload contract or merged fallback
  OwnIRBridge->>CI: Produce ownership findings
  CI-->>CI: Verify signatures and OWN001 for Drop
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding per-overload signature keys for stage 2 MOS resolution.
Description check ✅ Passed The description follows the required template and fills all required sections with concrete implementation, testing, issue, and checklist details.
Linked Issues check ✅ Passed The changes match #216’s requirements for sig-based overload summaries, fallback behavior, extractor stamping, specs, tests, and CI coverage.
Out of Scope Changes check ✅ Passed The code and docs changes all support the overload-signature MOS work, with no clear unrelated additions visible in the summary.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/plans-tasks-review-u77dfs

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: 540e07dc60

ℹ️ 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 ownlang/ownir.py
Comment thread frontend/roslyn/OwnSharp.Extractor/Program.cs
…n, extension-method sigs

The wpf-extractor CI job runs WITHOUT --flow-locals, so functions[] is
always empty there and the stage-2 assertions could never pass (first CI
run caught it). Move OverloadSigSample.cs and its assertions into the
dedicated flow-locals step (flow.json), rename its locals (made->opened,
s->dropped) clear of the step's existing silent-case guard, and pin the
exact leak wording plus the opened/probe silent cases.

Codex P2 x2, both verified real:
- call_key now canonicalizes the sig-less/unmatched fallback: a forward
  or return edge to a global::-qualified first-party callee lands on the
  bare-name merged summary exactly like _mos_lookup resolves a direct
  call, instead of going extern (unknown) and downgrading a resolvable
  must/fresh to OWN051/silence. Regression test: qualified forward to
  agreeing-consume overloads yields OWN002 (271/271).
- CanonicalSig canonicalizes through (ReducedFrom ?? m).OriginalDefinition
  so a reduced extension-method call site (receiver dropped from
  Parameters) and a constructed generic (type args substituted) produce
  the same string the declared functions[] record stamps — the precise
  per-overload contract applies instead of the merged fallback.

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

public static void Drop(string path)
{
var dropped = Open(path); // sig'd call -> the fresh overload's contract

@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: 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 @.github/workflows/ci.yml:
- Around line 260-271: Update the e2e assertion around the `Drop` finding to
match the specific dropped-result/`Drop` location in `OverloadSigSample.cs`,
rather than accepting any `OWN001` from that file. Also validate the call
operation’s `sig` structurally, using the expected `System.String` signature, so
the test proves overload-specific resolution and rejects missing or unmatched
call-side signatures.
🪄 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: b7a38f6a-5c0e-4d83-bde1-2d0ec608b1a8

📥 Commits

Reviewing files that changed from the base of the PR and between a5d611c and 540e07d.

📒 Files selected for processing (10)
  • .github/workflows/ci.yml
  • docs/notes/interprocedural-roadmap.md
  • docs/notes/interprocedural-tz.md
  • frontend/roslyn/OwnSharp.Extractor/Program.cs
  • frontend/roslyn/samples/OverloadSigSample.cs
  • ownlang/ownership.py
  • ownlang/ownir.py
  • spec/OwnIR.md
  • spec/ownir.schema.json
  • tests/test_ownir.py

Comment thread .github/workflows/ci.yml Outdated
Replace the two flow.json greps (which either side of the edge could
satisfy alone) with a structural check: the two SigOverloads.Open records
must carry exactly the (string) and (FileStream,bool) sigs, and Drop's
call op must carry callee/sig/result for the (string) overload — so a
missing or unmatched CALL-side sig fails on its own, not only via the
downstream OWN001 assertion. Dry-run locally against the extractor fact
shape, positive and negative.

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

Copy link
Copy Markdown

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@PhysShell
PhysShell merged commit ba59ccf into main Jul 11, 2026
38 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.

Interprocedural stage 2: per-overload signature keys (sig) in the MOS

3 participants