Skip to content

feat(identity): freeze finding-pattern/v1 with canonical vectors - #55

Merged
PhysShell merged 2 commits into
mainfrom
claude/complex-project-tasks-viyycs
Jul 28, 2026
Merged

feat(identity): freeze finding-pattern/v1 with canonical vectors#55
PhysShell merged 2 commits into
mainfrom
claude/complex-project-tasks-viyycs

Conversation

@PhysShell

@PhysShell PhysShell commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Что и зачем

Срез 0 работы над identity/provenance (Own.NET#266): сделать pattern-level идентичность контрактом с единственной реализацией и исполняемыми векторами, не изменив ни одного эмитируемого байта.

Рецепт sha1(path \x1f rule \x1f message)[:16] переезжает из viz/apply_verdicts в identity/pattern.py без изменений, а finding_id остаётся алиасом для overlay. Ничего в выводе не двигается — и в этом весь смысл: каждый сохранённый fp-verdicts.json ключуется этими байтами, guard свежести доказывает лишь то, что вердикты выносились против того же файла находок, а overlay, переставший совпадать, даёт пустой отчёт, а не ошибку. Тихий отказ заслуживает теста, а не комментария.

Векторы считались не той реализацией, которую проверяют

contracts/finding-pattern-v1.json — исполняемая половина контракта. Ожидаемые id получены независимой транскрипцией рецепта из текста доменного контракта и сверены со штатной apply_verdicts.finding_id до заморозки; совпали на всех девяти. Эта транскрипция осталась в тесте живой проверкой — векторы, сгенерированные собственной реализацией, согласны сами с собой и больше ни с чем.

Отдельными парами различимости закреплено то, что намеренно не нормализуется:

Пара Что доказывает
windows-style-pathposix-style-path разделитель пути — часть идентичности
posix-style-pathpath-case-upper регистр не сворачивается
message-with-digitsmessage-with-other-digits цифры не нормализуются
message-with-digitswhitespace-differs пробелы не схлопываются
posix-style-path = repeated-identical коллизия повторяющегося паттерна намеренна

Плюс UTF-8 для не-ASCII пути и сообщения, и разница между отсутствующим полем (ошибка) и пустым (хешируется).

Разграничение с SARIF-ключом

Записано в доменном контракте таблицей, в AGENTS.md и в docstring модуля, потому что оно уже один раз ввело в заблуждение. partialFingerprints["ownAudit/v1"]другое значение: нормализованное сообщение, полный digest, суффикс /ordinal для повторов. Это legacy-ключ корреляции GitHub. Одного ординала достаточно, чтобы дисквалифицировать его как идентичность: порядок подачи результатов не имеет права менять id. Новые fingerprints пойдут рядом с ним, а не вместо — иначе миграция сбросит историю всех alert'ов, попутно объявив это улучшением корреляции.

Non-goals

No normalized schema
No occurrence_id
No lineage_id
No provenance model
No SARIF fingerprint migration
No emitted-output changes

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

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

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

  • PYTHONPATH=. python3 identity/pattern.py --selftest — 9 векторов, 1 пара коллизии, 4 пары различимости
  • PYTHONPATH=. python3 identity/tests/test_pattern.py — включая побайтовую сверку алиаса apply_verdicts.finding_id на каждом векторе
  • Оба теста под -O (assert-stripping safety), как требует конвенция репозитория
  • viz/apply_verdicts.py --selftest — без изменений
  • Полный Linux-safe sweep из AGENTS.md — все 15 сьют проходят
  • Тест добавлен в обе фазы CI (обычную и -O)

Связанные issue

Refs PhysShell/Own.NET#266Slice 0: freeze finding-pattern/v1. Issue не закрывается: впереди перенос нормализатора с parity, схема с occurrence/provenance и модель lineage.


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added a standardized, deterministic identity for pattern-level findings.
    • Added canonical validation vectors covering path, rule, message, Unicode, whitespace, and empty-message handling.
  • Documentation

    • Clarified fingerprint compatibility requirements and distinctions between pattern identities and legacy SARIF correlation keys.
  • Tests

    • Added comprehensive identity validation tests and included them in continuous integration checks.

Slice 0 of the identity/provenance work (Own.NET#266): make the pattern-level
identity a contract with one implementation and executable vectors, WITHOUT
changing a single emitted byte.

The recipe — sha1(path \x1f rule \x1f message)[:16] — moves from
viz/apply_verdicts into identity/pattern.py unchanged, and finding_id stays as
the overlay-facing alias. Nothing about the output moves, which is the entire
point: every stored fp-verdicts.json is keyed by those bytes, the freshness
guard only proves the verdicts were judged against the same findings file, and
an overlay that stops matching yields an EMPTY REPORT rather than an error. A
silent failure mode earns a test, not a comment.

contracts/finding-pattern-v1.json is the executable half. Its vectors pin what
is deliberately NOT normalized — path separator, path case, digits and
whitespace in the message — each as its own distinctness pair, so a well-meant
cleanup fails a test instead of quietly re-keying every verdict in existence.
Also pinned: the intentional collision (two physical findings sharing
(path, rule, message) share an id, because one judged verdict covers the
repeated pattern), UTF-8 handling for non-ASCII paths and messages, and that a
MISSING field raises while an EMPTY one hashes.

The expected ids were not generated by the implementation under test. They were
computed from an independent transcription of the recipe and cross-checked
against the shipped apply_verdicts.finding_id before being frozen; the test
keeps that outside opinion as a live check, because vectors regenerated from
their own implementation agree with each other and with nothing else.

Recorded in the domain contract and AGENTS.md, because it has already misled
once: SARIF's partialFingerprints["ownAudit/v1"] is a DIFFERENT value — it
lower-cases the message, collapses digits and spaces, keeps the full digest and
appends a /ordinal suffix for repeats. It is a legacy GitHub-correlation key.
The ordinal alone disqualifies it as identity: presentation order must never
change an id. New fingerprints will go alongside it, never in place of it, or
the migration would reset every alert's history while claiming to improve
correlation.

Verified: new contract tests pass under python3 and -O; apply_verdicts selftest
unchanged; the full Linux-safe sweep from AGENTS.md — all 15 suites — passes.

Refs PhysShell/Own.NET#266.

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

coderabbitai Bot commented Jul 28, 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: 53 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 945d2a7a-c339-4359-b518-8e46135ac96e

📥 Commits

Reviewing files that changed from the base of the PR and between b36496f and 366a0c2.

📒 Files selected for processing (3)
  • identity/__init__.py
  • identity/pattern.py
  • identity/tests/test_pattern.py
📝 Walkthrough

Walkthrough

The change defines the finding-pattern/v1 fingerprint contract, centralizes ID computation in identity/pattern.py, updates verdict application to use it, adds executable vector and compatibility tests, and runs those tests in both standard and optimized CI modes.

Changes

Finding-pattern identity

Layer / File(s) Summary
Frozen identity contract and implementation
contracts/finding-pattern-v1.json, identity/pattern.py, AGENTS.md, docs/fp-judge/verdict-contract.md
Defines the SHA-1 recipe, canonical vectors, required fields, non-normalization rules, compatibility semantics, and distinction from the SARIF ownAudit/v1 fingerprint.
Verdict integration and executable validation
viz/apply_verdicts.py, identity/tests/test_pattern.py, .github/workflows/ci.yml
Routes finding_id through pattern_id_of, validates canonical vectors and overlay compatibility, and runs the new test under standard and optimized Python modes.

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

Possibly related issues

  • PhysShell/Own.NET issue 266 — Freezes the same finding-pattern/v1 and pattern_id foundation extended by this change.

Possibly related PRs

  • PhysShell/OwnAudit#9 — Introduces the CI structure for additional tests and python -O reruns used here.
  • PhysShell/OwnAudit#31 — Previously introduced the inline finding identity that this change centralizes in identity/pattern.py.

Sequence Diagram(s)

sequenceDiagram
  participant FindingRecord
  participant finding_id
  participant pattern_id_of
  participant fp_verdicts
  FindingRecord->>finding_id: path, rule, message
  finding_id->>pattern_id_of: compute canonical pattern ID
  pattern_id_of-->>finding_id: 16-character fingerprint
  finding_id->>fp_verdicts: match stored verdict overlay
  fp_verdicts-->>finding_id: verdict result
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: freezing the finding-pattern/v1 identity contract with canonical vectors.
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/complex-project-tasks-viyycs

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: b36496fa94

ℹ️ 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 viz/apply_verdicts.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: 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:
- Line 37: Apply the PYTHONUTF8=1 prefix consistently to the normal and
optimized identity test commands in .github/workflows/ci.yml at lines 37-37 and
57-57. Update the documented bare-script command in
identity/tests/test_pattern.py lines 1-14 and the self-test and CLI usage
examples in identity/pattern.py lines 107-108 and 157-158 to include
PYTHONUTF8=1.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9807e27a-3133-478a-979e-80510caaf48e

📥 Commits

Reviewing files that changed from the base of the PR and between 56c96c9 and b36496f.

📒 Files selected for processing (7)
  • .github/workflows/ci.yml
  • AGENTS.md
  • contracts/finding-pattern-v1.json
  • docs/fp-judge/verdict-contract.md
  • identity/pattern.py
  • identity/tests/test_pattern.py
  • viz/apply_verdicts.py

Comment thread .github/workflows/ci.yml
…proof

Two review findings, both reproduced before fixing.

1. AN INSTALLED `identity` PACKAGE SHADOWED OURS (Codex P2). Without
   `__init__.py` the directory is only a NAMESPACE portion: during the sys.path
   scan a namespace portion is remembered and the scan CONTINUES, so a regular
   package found later still wins -- inserting the repo root first does not
   help. `identity` is a real name on PyPI, so this is not hypothetical.
   Reproduced with a stand-in installed package: `ModuleNotFoundError: No
   module named 'identity.pattern'`, resolving to the other distribution. Adding
   the initializer fixes it; verified against the same stand-in.

2. THE TEST'S OWN OUTPUT COULD CRASH IT (CodeRabbit, with a correction). The
   claim was a missing PYTHONUTF8=1 prefix. Reading the vectors was never at
   risk -- every read passes `encoding="utf-8"` explicitly -- but the printed
   summary contained an em-dash, and under a legacy stdout encoding that raises
   UnicodeEncodeError. Reproduced with `PYTHONUTF8=0 LC_ALL=C`: the contract
   verified correctly and then the process died printing the result. A failing
   test that fails on its own output is worse than a failing test.

   Fixed at the source rather than documented around: the identity module and
   its test are now pure ASCII, including the docstring that the CLI branch
   prints. Both now pass under `PYTHONUTF8=0 LC_ALL=C`, so they no longer depend
   on the ambient encoding at all.

   The documented invocations do carry PYTHONUTF8=1, matching AGENTS.md. The CI
   lines deliberately do NOT: this workflow has never used the prefix on any of
   its sixteen suites, and adding it to only the two new lines would make them
   inconsistent with the rest while fixing nothing that (2) has not already
   fixed. If the runners' locale were ever non-UTF-8 that would be a repo-wide
   problem, not this slice's.

Verified: both hostile scenarios now pass; the full Linux-safe sweep -- now 16
suites -- passes, plus -O.

Refs PhysShell/Own.NET#266.

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

Copy link
Copy Markdown
Owner Author

Учтено в 366a0c2, с одной поправкой по сути.

Чтение векторов под угрозой не было — все чтения идут с явным encoding="utf-8". Проблема была в выводе: строка итога содержала длинное тире, и под legacy-кодировкой stdout это UnicodeEncodeError. Воспроизвёл: с PYTHONUTF8=0 LC_ALL=C контракт проверялся корректно, а затем процесс падал, печатая результат. Падающий тест, который падает на собственном выводе, хуже просто падающего теста.

Починил в источнике, а не обошёл документацией: модуль identity и его тест теперь полностью ASCII, включая docstring, который печатает CLI-ветка. Оба проходят под PYTHONUTF8=0 LC_ALL=C — зависимости от окружения больше нет вовсе.

Документированные команды запуска PYTHONUTF8=1 получили, как и требует AGENTS.md. Строки CI — намеренно нет: в этом workflow префикс не используется ни на одной из шестнадцати сьют, и добавление его только к двум новым сделало бы их несогласованными с остальными, ничего при этом не починив сверх того, что уже сделано выше. Если локаль раннеров когда-нибудь окажется не UTF-8, это будет проблемой всего репозитория, а не этого среза, — и решать её надо одним движением для всех, а не точечно там, где недавно смотрели.


Generated by Claude Code

@PhysShell
PhysShell merged commit ee456b8 into main Jul 28, 2026
3 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