Skip to content

fix(tests): the validation ledger writer refuses a ledger its own verify rejects - #383

Merged
PhysShell merged 1 commit into
mainfrom
fix/validation-ledger-writer-contract
Oct 1, 2026
Merged

PhysShell merged 1 commit into
mainfrom
fix/validation-ledger-writer-contract

Conversation

@PhysShell

Copy link
Copy Markdown
Owner

Что и зачем

python tests/test_ownir_validation_fixtures.py --write завершался с кодом 0 и записывал реестр, который следующая же проверка отвергает. Причина: в 207 контролях версия была зашита литералом 0, и при любом изменении OWNIR_VERSION все они отклоняются на воротах версии раньше, чем срабатывает проверяемое правило (58 принимаемых контролей становятся отказами, accepted: 2 из 294). Теперь контроли берут OWNIR_VERSION, а писатель отказывается фиксировать реестр, не проходящий собственные инварианты.

При версии 0 закоммиченный реестр побайтово прежний: фикстуры не меняются, словарь OwnIR не затронут.

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

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

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

  • python tests/run_tests.py
  • ruff check . и mypy
  • селфтесты затронутых скриптов (python scripts/<...>.py --selftest)

Linux (WSL), ruff 0.15.8, mypy 1.19.1.

  • Отрицательный контроль: новые контроли без исправления падают — FAIL[version-agnostic]: 58 control(s) change their verdict when OWNIR_VERSION moves.
  • Воспроизведение дефекта на чистом main: поднять OWNIR_VERSION до 1, --write → код 0, затем проверка → FAIL[ledger-category].
  • cargo test -p own-ir (Rust-replay реестра) — зелёный: реестр не изменился.
  • Полный python tests/run_tests.py гонялся до коммита на дереве с обоими исправлениями (этим и соседним, про repro-артефакты); единственное падение там — контроль P-037 «dirty tree», который на закоммиченном дереве проходит.

Связанные issue

Нет. Найдено при пробном bump OWNIR_VERSION в исследовательской ветке; сам bump сюда не входит.

Чеклист

  • изменение покрыто тестом/селфтестом (или объяснено, почему нет)
  • README/docs обновлены при необходимости
  • коммиты в conventional-commit стиле (feat:, fix:, docs: …)

Документация не требуется: поведение --write при годном реестре прежнее.

🤖 Generated with Claude Code

…ify rejects

`tests/test_ownir_validation_fixtures.py --write` exited 0 after writing a
ledger that the very next verify run rejected. The trigger is any change of
`OWNIR_VERSION`: 207 controls spelled the version as the literal `0`, so once
the constant moves every one of them is refused at the version gate before the
rule it exists to exercise can run. 58 acceptance controls flip to rejections
and the writer commits the result (accepted: 2 of 294).

- the controls say `OWNIR_VERSION`, not a literal; at version 0 the committed
  ledger is byte-identical, so no fixture moves
- a new control rebuilds the ledger with the version shifted on both sides
  (the controls and the strict door) and requires every verdict and category
  to hold
- the invariants live in one function shared by verify and `--write`, and the
  writer refuses to commit a ledger that fails them

Negative control: with the new controls and without the fixes, verify fails
with `FAIL[version-agnostic]: 58 control(s) change their verdict`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@PhysShell
PhysShell merged commit 5323dd4 into main Oct 1, 2026
68 checks passed
PhysShell added a commit that referenced this pull request Oct 1, 2026
…sion

`tests/check_fix_candidates_facts.py` asserted `ownir_version == 0` under the
message "ownir_version must stay 0". What it meant is that `--fix-candidates`
is additive metadata and does not move the vocabulary version; what it checked
was a literal, which held only until the vocabulary first moved. OwnIR v1 moved
it, and the `C# leak extractor (Roslyn) -> OwnIR -> core` job went red on that
line — with the extractor doing exactly the right thing.

It now checks the claim: the flag-on facts are stamped with the core's current
OWNIR_VERSION, and with the same value as the flag-off facts.

This is the third control of this shape the bump has found (the validation
ledger in #383, the instrument's generated facts in this branch), and the only
one that needed the server to find it: the script takes the extractor's output
as its argument, so it is not part of `tests/run_tests.py` and no local run of
that suite could reach it. The job's steps were then run locally as written,
from this one to the end of the job, on a Linux clone of the committed tree.

tests/goldens/README.md records the golden's second amendment: one line,
`"ownir_version": 0` -> `1`, made in the vocabulary commit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
PhysShell pushed a commit that referenced this pull request Oct 1, 2026
…rch promotion onto main, strict-door binding included)

OWN053 "orphaned awaitable": a local initialised by an un-awaited Task / ValueTask invocation of an effectful operation (the unwrapped result is a real disposable, or the member is a connection / transaction lifecycle call) that is never referenced again in its member. Default-on advisory in both engines with an identical message, rendered as a warning, never the exit code, hidden at --verbosity quiet; no automatic fix. The scope is frozen as measured in ownership-semantics-lab H-29: discards, expression statements, stored / passed / returned awaitables and lambdas are untouched; new lifecycle members enter only by witnesses.

Provenance: a re-port onto main 5323dd4 of research/ownership-semantics-lab-v1 commits ab2964f (promotion) and 298b305 (P-OWN053-DOOR), carrying ONLY the OWN053 hunks. Unlike a file-level copy of those two commits, this port does not bring the research branch's content along: the extractor gains one detector (CollectOrphanedAwaitables), one holder and the additive facts branch instead of 1,900 lines of env-gated research seams; ownlang/ownir.py gains the family set, the strict-door block, the check_facts call and the finding builder instead of the H-20 / resource-effects E3 / P-037-X seams; spec/OwnIR.md and the schema gain §9, the §4.2 note, the orphanedAwaitable / orphanFamily definitions and nothing of params[].ordinal or flag_var; tests/test_ownir_validation_fixtures.py keeps main's #383 writer contract and gains the orphaned_awaitables section on top of it; tests/test_p037_evidence.py is untouched because main has none of the research read sites; the Rust diagnostics catalogue and the diagnostics ledger (47 -> 48) are included, which the file-level copy had lost.

Extractor: the sites are collected into the ADDITIVE top-level facts list orphaned_awaitables (absent when there is no site, so such a document is byte-identical to the pre-OWN053 shape; ownir_version unchanged). On the committed fixture corpus/ownership-lab/h29/fx/Orphan.cs the production build finds exactly the five frozen primary sites of the H-29 scan and none of the eleven twins; the facts equal the research build's modulo the research-only params[].ordinal field.

Strict doors: both load() and the Rust strict door validate the list last in BR-D1 order (array of objects; non-empty local / callee as identity, file string, line in the §4.2 domain, column as every other column, method / result_type string-or-null, family from the closed set as vocabulary). cp1 ledger 294 -> 344 controls, appended insertion-stable on top of #383's writer; the Rust validation replay reports no permissive accept and no category mismatch. Schema bound to sourceLine / sourceColumn / orphanFamily (pinned to ownlang/ownir.py::_ORPHAN_FAMILIES); binding map BOUND; coordinate census door slots; checkpoint documents regenerated.

Verification on this tree: the fixture through both CLIs (5 advisory OWN053, 0 findings, exit 0, Python == Rust); three malformed documents refused by both CLIs with exit 2 (corpus/ownership-lab/h29/door); CLI fixtures, verdict goldens (one new synthetic case), diagnostics ledger and repro digests regenerated; full Python suite and cargo test --release green; the extractor builds with main's pre-existing warning only.

Not included (registered in Own.NET-paperwork): P-OWN053-WORDING (family-specific message tails) stays open and precedes any family A/B expansion; discards / expression statements / family-B expansion / autofix / H-26A are not earned.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Am9eQwzNfbugH72eVKetC2
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.

1 participant