Skip to content

execution surfaces ADR + evidence coverage for OWN015/OWN016/OWN005#164

Merged
PhysShell merged 6 commits into
mainfrom
claude/ownnet-execution-surfaces-adr-8kyc0n
Jul 3, 2026
Merged

execution surfaces ADR + evidence coverage for OWN015/OWN016/OWN005#164
PhysShell merged 6 commits into
mainfrom
claude/ownnet-execution-surfaces-adr-8kyc0n

Conversation

@PhysShell

@PhysShell PhysShell commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Что и зачем

Заносит ADR по «execution surfaces» (итог аудита идеи Forth-like stack VM: reject VM, adopt typed primitive registry + расширение diagnostics.Evidence) и реализует его первую ступень: подключает простаивавшую evidence-машинерию к flow-анализу. Три диагностики теперь несут структурированную reachability-цепочку (рендерится как note:-строки / SARIF codeFlows):

  • OWN015 — stack-backed буфер утекает через return → шаги allocated (место аллокации буфера) + escapes by return;
  • OWN016 — stack-backed буфер уносится в долгоживущего владельца через consume-вызов → allocated + consumed by call;
  • OWN005 — use/return после move → шаг moved here. State теперь хранит per-RID место move (line, exact); на control-flow merge move по разным строкам на разных путях честно помечается «one of several paths», а не именует строку одного пути.

Семантику проверок не меняли: evidence лишь аннотирует существующие findings, не несёт lattice-состояния и не влияет на вердикт. Плюс ADR и исполнимое ТЗ (docs/tasks/evidence-coverage.md).

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

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

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

  • python tests/run_tests.py — зелёный (добавлен tests/test_evidence_coverage.py: slice + human-render golden + merge-point honesty + empty-evidence invariant, свёрнут в аггрегатор)
  • ruff check . и mypy — чисто, без новых # type: ignore

Связанные issue

Нет связанного issue.

Чеклист

  • изменение покрыто тестом/селфтестом — tests/test_evidence_coverage.py
  • README/docs обновлены — «Where it cheats» дополнен честной пометкой про частичность merge-point evidence; добавлены ADR и ТЗ
  • коммиты в conventional-commit стиле (feat:, docs:)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added richer diagnostic evidence for several ownership and escape issues, including clearer note output in problem reports.
  • Bug Fixes

    • Improved use-after-move reporting so evidence points to the correct move site, including control-flow merge cases.
    • Added more precise evidence for certain allocation, consumption, and return-related diagnostics.
  • Documentation

    • Clarified how diagnostic evidence behaves on merge paths and when evidence may be partial.
  • Tests

    • Added coverage for evidence output and rendering, including regression checks and empty-evidence behavior.

Record the audit outcome for the "Forth-like stack VM as internal IR"
idea: reject the stack VM / stack-DSL, adopt a problem-oriented execution
surface (typed primitive registry, extended structured evidence via
diagnostics.Evidence, per-finding explain later). Includes rationale,
target design, acceptance criteria, non-goals, evolution ladder and a
trigger table for reconsidering Datalog / stack bytecode.
@coderabbitai

coderabbitai Bot commented Jul 2, 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: 37 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: 513baf2a-2908-4f17-8ace-2c2dfd046c47

📥 Commits

Reviewing files that changed from the base of the PR and between 1155ac4 and 92a48e2.

📒 Files selected for processing (4)
  • README.md
  • docs/tasks/evidence-coverage.md
  • ownlang/analysis.py
  • tests/test_evidence_coverage.py
📝 Walkthrough

Walkthrough

This PR threads structured Diagnostic.evidence through OWN005 (use-after-move), OWN015, and OWN016 diagnostics by adding State.moved_at provenance tracking with CFG-join merging, adds a dedicated evidence-coverage test suite wired into the test runner, and adds README, task-spec, and ADR documentation.

Changes

Evidence Coverage Implementation

Layer / File(s) Summary
State.moved_at provenance and join logic
ownlang/analysis.py
Adds moved_at to State, deep-copies it in copy(), and merges it deterministically across joins via a new _join_moved_at helper.
Structured evidence emission in diagnostics
ownlang/analysis.py
Extends err() with an evidence parameter, adds _moved_evidence(), and attaches evidence tuples to OWN005 (move-site), OWN015 (acquire/escape), and OWN016 (acquire/consume) diagnostics.
Evidence coverage test suite
tests/test_evidence_coverage.py, tests/run_tests.py
New self-contained test module asserts evidence ordering, move-site precision, merge-point inexactness, and empty-evidence invariants; wired into run_tests.py aggregation.
Documentation: README, task spec, and ADR
README.md, docs/tasks/evidence-coverage.md, AGENTS.execution-surfaces.md
README clarifies evidence exactness/partial coverage; adds a task spec for evidence coverage work; adds an ADR rejecting a stack VM IR in favor of a typed execution-surface/evidence-extension approach.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Analyzer
  participant State
  participant Diagnostic
  participant Test as test_evidence_coverage

  Analyzer->>State: record moved_at(rid, line, exact) on MoveInto
  Analyzer->>State: join moved_at across CFG paths (_join_moved_at)
  Analyzer->>Analyzer: _moved_evidence() builds evidence tuple
  Analyzer->>Diagnostic: err(code, evidence=...)
  Diagnostic-->>Analyzer: render() appends note: lines
  Test->>Analyzer: analyze fixture source
  Test->>Diagnostic: inspect .evidence and render() output
Loading

Possibly related PRs

  • PhysShell/Own.NET#118: Introduces the Evidence/Diagnostic.evidence model that this PR wires concrete analyzer provenance into.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the ADR plus evidence coverage work for OWN015/OWN016/OWN005.
Description check ✅ Passed The description matches the required template and includes the purpose, type, verification, issue status, and checklist.
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/ownnet-execution-surfaces-adr-8kyc0n

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.

claude added 2 commits July 2, 2026 20:32
…es ADR)

Executable ТЗ derived from AGENTS.execution-surfaces.md §3/§5: wire the
idle Diagnostic.evidence machinery for three flow diagnostics
(OWN015/OWN016 escape+lifetime, OWN005 use-after-move), with a golden
human-render test and an honest README note on partial merge-point
evidence. Grounded in concrete emit sites in ownlang/analysis.py.
Wire the idle diagnostics.Evidence machinery into the flow analysis so
three findings carry a structured reachability slice (rendered as note:
lines / SARIF codeFlows), per the execution-surfaces ADR §3/§5:

- OWN015: stack-backed buffer escapes by return -> acquire (buffer alloc
  site) + escape (return) steps.
- OWN016: stack-backed buffer consumed into a longer-lived owner ->
  acquire + consumed-by-call steps.
- OWN005: use/return after move -> move-site step. State now records a
  per-RID move site (line, exact); at a control-flow merge a move at
  different lines on different paths is labelled one-of-N rather than
  naming a single path's line.

No semantic change: evidence only annotates existing findings, carries no
lattice state, and changes no verdict. Adds tests/test_evidence_coverage.py
(slice + human-render golden + merge-point honesty + empty-evidence
invariant) folded into run_tests.py, and an honest README 'Where it
cheats' note on partial merge-point evidence. Gate green: run_tests,
ruff, mypy ownlang; no new type: ignore.
@PhysShell PhysShell changed the title docs: add execution-surfaces ADR (reject Forth stack VM as internal IR) execution surfaces ADR + evidence coverage for OWN015/OWN016/OWN005 Jul 2, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review
@codex review

Requesting a review of the evidence-coverage change (commit 915b35f). Focus areas:

  • ownlang/analysis.py: the new per-RID moved_at map (State.moved_at, _join_moved_at) — correctness at control-flow merges and no impact on the worklist fixpoint's convergence / the existing join() loan & handle→RID invariants.
  • Evidence attached to OWN015 / OWN016 / OWN005: does it point at the right acquire/escape/move source lines, and is the merge-point "one of several paths" labelling honest?
  • That evidence is purely additive — no verdict/semantics change to any existing check.

Generated by Claude Code

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Git / PR context =="
git rev-parse --short HEAD
git log --oneline --decorate -n 5

echo
echo "== Changed files in commit 915b35f =="
git show --stat --name-only --format=fuller 915b35f

echo
echo "== Diff for ownlang/analysis.py in 915b35f =="
git diff 915b35f^ 915b35f -- ownlang/analysis.py

echo
echo "== Find evidence-related files =="
fd -i 'analysis.py|diagnostic|evidence|sarif|render|test_evidence_coverage.py|run_tests.py|README|adr|evidence-coverage' .

echo
echo "== AST outline for ownlang/analysis.py =="
ast-grep outline ownlang/analysis.py --view expanded || true

echo
echo "== Relevant snippets from ownlang/analysis.py (first 260 lines) =="
sed -n '1,260p' ownlang/analysis.py

echo
echo "== Relevant snippets from ownlang/analysis.py (261-620 lines) =="
sed -n '261,620p' ownlang/analysis.py

echo
echo "== Relevant snippets from tests/test_evidence_coverage.py =="
sed -n '1,260p' tests/test_evidence_coverage.py

echo
echo "== Search for OWN015/OWN016/OWN005 and evidence APIs =="
rg -n -C3 'OWN015|OWN016|OWN005|Evidence|evidence|codeFlow|note:' ownlang tests README.md docs

echo
echo "== If present, diagnostics/evidence implementation =="
for f in $(fd -i 'diagnostic*.py|*evidence*.py|sarif*.py|render*.py' ownlang tests docs .); do
  echo
  echo "---- FILE: $f ----"
  sed -n '1,260p' "$f"
done

Length of output: 158054


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== ownlang/analysis.py: _apply_effect tail =="
sed -n '616,690p' ownlang/analysis.py

echo
echo "== ownlang/diagnostics.py =="
sed -n '190,320p' ownlang/diagnostics.py

echo
echo "== Focused diff around tests/run_tests.py =="
git diff 915b35f^ 915b35f -- tests/run_tests.py

Length of output: 10206


@PhysShell Reviewed 915b35f with the requested focus. I don’t see any blocking issues here.

What I checked:

  • State.moved_at / _join_moved_at look safe for merges and fixpoint convergence

    • moved_at is copied in State.copy() and joined separately in join() without touching the existing loans or handle_rid invariants.
    • Line 161 _join_moved_at() is monotone for the worklist: for a given RID it only goes from “absent” → (line, True) or from exact/disagreeing inputs → (min_line, False). I don’t see an oscillation path.
    • The existing hard invariants remain where they matter: loans still assert identical active-loan sets at merge, and handle_rid still asserts the 1:1 mapping. moved_at correctly avoids pretending it has that kind of invariant.
  • Evidence on OWN015 / OWN016 / OWN005 points at the right source sites

    • Line 558 OWN015: allocation comes from ins.sym.buffer.line, escape from ins.line on return — that matches the intended acquire → escape chain.
    • Line 622 OWN016: allocation comes from sym.buffer.line, consume from the invoke line — correct for the consume path.
    • Line 437 records the move site on MoveInto, and Lines 273 / 539 reuse that for both use-after-move and return-after-move OWN005.
  • Merge-point honesty looks correct

    • Line 167 intentionally keeps a deterministic representative line but flips exact=False on disagreement.
    • Line 237 then renders that as "moved here (on one of several paths)", which is the right “don’t overclaim precision” behavior.
  • The change appears purely additive

    • Line 219 keeps evidence defaulting to (), so unchanged call sites preserve prior behavior.
    • The self.silent early return still happens before appending diagnostics, so fixpoint emission behavior is unchanged.
    • _apply_effect() still performs the same state transition to ESCAPED; MoveInto still marks the source RID as MOVED. I didn’t see any verdict-path changes beyond attaching metadata.
  • Tests are aligned with the risk

    • tests/test_evidence_coverage.py covers exact evidence for OWN015 / OWN016 / OWN005, merge-point honesty, and the empty-evidence invariant.
    • tests/run_tests.py now includes that coverage in the aggregate suite.

Looks good to me. Approving.
[approve]

@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: 915b35faf6

ℹ️ 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/analysis.py Outdated
st.var[src_rid] = {VarState.MOVED}
# remember where the move happened, so a later use/return-after-move
# (OWN005) can point evidence at the move site. A single move is exact.
st.moved_at[src_rid] = (ins.line, True)

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 the original move site for OWN005 evidence

When a value is moved a second time, _consume_like first reports the line's OWN005 using the original move site, but this assignment then overwrites moved_at for the RID. A later use or return of that same handle will render moved here at the failed second move rather than at the move that actually made the resource unavailable, so fixing the annotated line can leave the real use-after-move unexplained. Keep the first recorded move site, or only replace it when the move is valid.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Good catch — fixed in 1155ac4. moved_at is now written only on a real ownership transfer (source still OWNED before the move), so a failed second move no longer overwrites the first move site. A later use/return-after-move is explained by the move that actually consumed the resource. Added a double-move regression to tests/test_evidence_coverage.py (a use after move a; move a; reports its evidence at the first move line, not the failed second one).


Generated by Claude Code

Codex P2: a second move of an already-moved handle is itself an OWN005,
but the move-site record was overwritten with that failed move's line. A
later use/return-after-move then rendered 'moved here' at the failed
second move instead of the move that actually consumed the resource.
Record moved_at only on a real ownership transfer (source still OWNED),
so the first move site is preserved. Adds a double-move regression to
tests/test_evidence_coverage.py.

@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: 2

🤖 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/tasks/evidence-coverage.md`:
- Around line 88-99: The `moved_at` sketch is missing the exactness flag needed
to distinguish an exact move line from a merged representative. Update the
`State.moved_at` shape and every reference to it in `State.copy()`, `join()`,
`MoveInto`/consume-like transitions, and the OWN005 evidence emission in
`ownlang/analysis.py` so the stored value carries exactness and the example uses
that flag instead of assuming `dict[int, int]`. Keep the join behavior for
multiple move paths, but mark merged entries as approximate rather than
inventing a precise line.

In `@README.md`:
- Around line 628-636: Update the merge-point wording in README so it states
that exact move-site evidence is preserved when all incoming paths agree on the
same line, and only conflicting branches should be described as “moved here (on
one of several paths)”. Adjust the explanatory text around the control-flow
merge behavior to reflect the union logic in ownlang/analysis.py without
implying that every merge loses precision.
🪄 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: 2993bd2c-2c04-4664-8f4e-4aa51207493f

📥 Commits

Reviewing files that changed from the base of the PR and between 873469d and 1155ac4.

📒 Files selected for processing (6)
  • AGENTS.execution-surfaces.md
  • README.md
  • docs/tasks/evidence-coverage.md
  • ownlang/analysis.py
  • tests/run_tests.py
  • tests/test_evidence_coverage.py

Comment thread docs/tasks/evidence-coverage.md Outdated
Comment thread README.md Outdated
claude added 2 commits July 2, 2026 22:14
… shape

CodeRabbit review nits (both docs-only):
- docs/tasks/evidence-coverage.md: the moved_at sketch showed dict[int, int];
  update it to the implemented dict[int, tuple[int, bool]] with the exactness
  flag, the record-only-on-real-transfer rule, and the exact/inexact OWN005
  label in the example.
- README 'Where it cheats': the wording implied any merge loses precision;
  clarify that exact evidence is preserved when all incoming paths agree on the
  move line, and only disagreeing branches degrade to 'one of several paths'.

No code change.
Symmetric counterpart to moved_at: a per-RID acquired_at (line, exact)
map recorded when a resource is minted (Acquire, AcquireBuffer, MoveInto
destination), threaded through State.copy() and the shared _join_sites
merge helper (renamed from _join_moved_at, now used for both provenance
maps). leak_check attaches an 'acquired here' step so an OWN001 leak --
reported at the function exit / a return -- points at the actionable open
site instead of the dead end at function end.

A leaked owned parameter is minted with no in-body site and carries no
step (honest). An acquire site is effectively always exact: a RID is
minted at a single acquire, so unlike a move it cannot disagree across
paths. Extends tests/test_evidence_coverage.py (leak acquire step,
leaked-param empty, move-destination leak) and switches the
empty-evidence invariant anchor to OWN003. README + task spec updated.

No semantic change: evidence only annotates existing findings. Gate
green: run_tests, ruff, mypy ownlang; no new type: ignore.

Copy link
Copy Markdown
Owner Author

@coderabbitai review

New commit 92a48e2 adds OWN001 acquire-site evidence — the symmetric counterpart to moved_at. Worth a look:

  • ownlang/analysis.py: new State.acquired_at (per-RID (line, exact)), recorded at mint sites (Acquire, AcquireBuffer, MoveInto destination), threaded through copy() and the shared _join_sites helper (renamed from _join_moved_at, now used for both provenance maps).
  • leak_check attaches an "acquired here" step to OWN001, pointing at the open site instead of the function exit; a leaked owned parameter correctly carries no step.
  • Purely additive — no verdict/semantics change; gate green (run_tests, ruff, mypy ownlang, no new # type: ignore).

Generated by Claude Code

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Log =="
git log --oneline --decorate -n 8

echo
echo "== Diff for ownlang/analysis.py in 92a48e2 =="
git diff 92a48e2^ 92a48e2 -- ownlang/analysis.py

echo
echo "== Diff for other files in 92a48e2 =="
git show --stat --name-only 92a48e2

echo
echo "== Full diff 92a48e2 =="
git diff 92a48e2^ 92a48e2

Length of output: 23474


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '380,430p' ownlang/analysis.py
echo "---"
sed -n '1,40p' ownlang/diagnostics.py | rg -n 'class Evidence' -A 10
echo "--- err() signature ---"
rg -n 'def err' ownlang/analysis.py -A 15
echo "--- mint() ---"
rg -n 'def mint' ownlang/analysis.py -A 10
echo "--- _sym_by_id ---"
rg -n '_sym_by_id' ownlang/analysis.py -A 10

Length of output: 2863


🏁 Script executed:

#!/bin/bash
set -euo pipefail
grep -n "class Evidence" -A 10 ownlang/diagnostics.py
echo "--- err ---"
grep -n "def err" ownlang/analysis.py -A 15
echo "--- mint ---"
grep -n "def mint" ownlang/analysis.py -A 12
echo "--- _sym_by_id full ---"
grep -n "_sym_by_id" ownlang/analysis.py -A 15

Length of output: 5945


🏁 Script executed:

#!/bin/bash
set -euo pipefail
grep -n "move-destination\|dst_rid\|MoveInto" tests/test_evidence_coverage.py -A 5 -B 5
echo "---full test diff context---"
sed -n '1,260p' tests/test_evidence_coverage.py

Length of output: 509


🏁 Script executed:

#!/bin/bash
sed -n '1,260p' tests/test_evidence_coverage.py

Length of output: 9974


🏁 Script executed:

#!/bin/bash
grep -n "leak_check" ownlang/analysis.py -B3 -A3

Length of output: 1120


@PhysShell Reviewed 92a48e2 — looks correct, and I don't see anything blocking.

What I checked:

  • State.acquired_at mirrors moved_at faithfully. Same dict[int, tuple[int, bool]] shape, copied in State.copy(), and merged via the renamed _join_sites helper (Lines 169–182 in the new file), which is now shared by both moved_at and acquired_at in join(). The rename is a clean, well-scoped refactor — docstring updated, both call sites updated, no behavior change to the merge rule itself (earliest line wins deterministically, disagreement flips exact=False).
  • Mint sites are correct and consistent: Acquire (records at ins.line), AcquireBuffer (same), and the MoveInto destination (dst_rid, at the move's line) — all recorded as exact=True at write time, only becoming inexact if a later merge disagrees.
  • The "acquire site is effectively always exact" claim holds up structurally. Since RID is id(sym) and a given symbol is minted exactly once, acquired_at[rid] can't legitimately disagree across merging paths — the inexact branch in _join_sites stays reachable only defensively/symmetrically with moved_at, which does need it.
  • _acquired_evidence() correctly returns () for a leaked owned parameter — no in-body mint site to point at, and the _OWN001_PARAM test confirms it.
  • leak_check() wiring is correct at both call sites (end-of-function fixpoint pass and before-Return) — both pass the live st that already carries the populated acquired_at map, so the evidence reflects the converged state, not a stale snapshot.
  • Purely additive: only an evidence= kwarg was added to the existing OWN001 err() call; the leak detection condition (VarState.OWNED in states) itself is untouched.
  • Empty-evidence invariant anchor correctly moved to OWN003 (double-release) now that OWN001 legitimately carries evidence in most cases — test still asserts no note: lines render for an evidence-free diagnostic.
  • Tests in tests/test_evidence_coverage.py line up exactly with the implementation (acquire-site line, leaked-param empty-evidence, shifted invariant anchor).

Nice symmetric extension of the pattern from the previous commit. Approving.

[approve]

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