Skip to content

feat(numerics): атомарные исходы, per-invocation план и capability manifest (#292) - #311

Merged
lemone112 merged 7 commits into
mainfrom
agent/numerical-plan-evidence-292
Jul 12, 2026
Merged

feat(numerics): атомарные исходы, per-invocation план и capability manifest (#292)#311
lemone112 merged 7 commits into
mainfrom
agent/numerical-plan-evidence-292

Conversation

@lemone112

@lemone112 lemone112 commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

Closes #292. Owner: #289.

Root

OutwardIntervalV1::try_new (форма без доказанности) повышался classify_at_least_v1 до Determinate-гарантии; legacy Glow возвращался как Determinate со слабой provenance внутри типа «гарантии»; WASM/FFI вручную реконструировали cross-product profile×guarantee×status; registry не отделял capability от compiled invocation.

Что сделано (по live-acceptance #292/#289)

  • Result truth: NumericalDecisionV1 атомарен — Determinate{sealed BitExact} | Compatibility{registered release_id + LegacyPlatformDependentV1} | Indeterminate; незаконные комбинации непредставимы типами; evidence минтится только registry-owned минтером (приватная печать).
  • Plan: RoleSpec::Glow несёт typed NumericalExecutionModeV1 (resolver без plan-lookup в hot path); numerical_plan.rs — invocation identity (opaque node bytes + site + локальный ordinal), canonical derived-проекция + FNV drift-checksum; NamedRoleTable::numerical_plan_v1() — точная биекция с Glow-ролями.
  • Capability: manifest по канону ARCH/NUMERICS: отделить package capabilities, compiled execution plan и result evidence #289 (length-prefixed preimage, домен-сепараторы); conformance pack 3.0.0numericalCapabilities вместо numericalSites[].legacyProfile; пять vector-семейств нетронуты, packDigest прежний.
  • Adapters: WASM/FFI маппят атомарный исход напрямую (cross-product удалён); wire-байты и JSON прежние; additive numericalCapabilityManifest() в WASM/npm; verifier с независимым JS FNV-оракулом; release-manifest schema 2 + read-back в publish.yml.
  • Removal: classify_at_least_v1/AtLeastDecisionV1/DecisionGuaranteeV1 удалены; два compile_fail doc-теста фиксируют миграцию (E0432, E0451 верифицированы standalone).

RED → GREEN

Структурный RED (E0425/E0433: несуществующие типы нового контракта) воспроизведён до реализации; RED-группы Issue: биекция/permutation/rename (semantic), legacy=Compatibility (glow/numerics), canonical manifest (numerics) — все GREEN без ослабления.

Proof ledger

  • Property: план-checksum permutation-invariant при неизменном порядке entries(); arb_config генерирует Glow (оба mode); ordinals 0,1 на synthetic повторе (node,site).
  • Frozen versioned encoding vector v1 плана (+ его checksum 49e5b6b7) — encoding как внешний контракт.
  • Мутационные пробы: mode-tag из preimage (убит frozen-вектором), глобальный ordinal (убит), потеря release в манифесте (убит core+conformance).
  • Differential: labui golden byte-identical; second-client (acme) получил Glow и остался byte/status-identical; npm 106/106 без regen; wasm-boundary golden непересняты; headless Chrome 12/12; release:verify (npm@11.9.0) зелёный.

API drift

Breaking Rust API (crate не опубликован на crates.io): перечислено в CHANGELOG. Wire/npm/config fingerprint/цвета/CSS/adaptive trace — без изменений.

Performance (A/B, main 9ac7785 ↔ branch, criterion s=10)

glow stable: 84–106ns → 81–92ns; stable exact-noop: 268–371ns → 250–252ns; legacy base: ~4.8–5.4µs → ~4.6–5.0µs — в пределах шума, регрессии нет; план не в resolve/frame path. WASM: raw 434,158 B, gzip 184,320 B; npm tarball 235,860 B против baseline 0.10.0 211,922 B (+11.3% — включает и #307 appearance-граф, и manifest/plan поверхности; бюджеты — Gate 10 по baseline).

7-lens

  1. SSOT: capability/plan/evidence — три типа, один registry-источник; 2) математика: новых чисел нет, encoding версионирован; 3) numerics: exact bytes, checksum — drift-sentinel, не trust identity; 4) API: breaking только неопубликованный Rust, адаптеры байт-идентичны; 5) tests: RED кусался, пробы убиты, анти-вакуум и frozen vector; 6) perf: без регрессий, hot path без lookup; 7) docs: CHANGELOG/README×4/ADR-0004/migrations/verification-map, без обещаний PlatformCharacterized/outward determinate.

Rollback

Revert одного squash-коммита; публичные байты не менялись.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Новые возможности

    • Добавлен публичный capability manifest с описанием численных возможностей и контрольной суммой.
    • Добавлена компиляция канонического численного плана с режимами стабильного и явного legacy-совместимого выполнения.
    • Результаты Glow теперь представлены атомарными исходами: определённый, совместимый или неопределённый.
  • Изменения API

    • Обновлены Rust-, WASM- и TypeScript-интерфейсы для новой модели решений.
    • Удалены устаревшие типы и классификаторы численных гарантий.
  • Форматы и проверка

    • Conformance Pack обновлён до версии 3.0.0 с numericalCapabilities.
    • Усилена проверка релизных манифестов и независимая проверка контрольных сумм.
  • Документация

    • Обновлены руководства, changelog и описание возможностей Glow.

lemone112 and others added 6 commits July 12, 2026 16:57
…292)

package capability ≠ compiled invocation plan ≠ result evidence:

- CompiledNumericalPlanV1 компилируется fail-closed из machine-readable
  registry-строки site (stable = [exact, refuse]; legacy только при
  объявленном compatibility profile); план не содержит результата;
- SoundIntervalEvidenceV1 — запечатанное интервальное свидетельство
  (конструктор приватен; production-производитель появится только вместе с
  допущенным sound-bound backend'ом): classify_at_least_v1 принимает только
  его, голый caller-created интервал больше не повышается до
  Determinate-гарантии;
- OutwardIntervalV1 честно понижен до интервала-заявления (проверка формы,
  не доказанность);
- glow::solve_screen_alpha_for_dj исполняет ветви строго по скомпилированному
  плану — порядок методов задаёт registry, не рукописный match; поведение
  байт-идентично (glow 32/32, полный workspace зелёный).

Wire-ключи и WASM/npm поверхности не изменены.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…BitExact, plan/manifest ядро

Core компилируется, тесты ядра зелёные (RED-группы #292 включены).
Осталось: conformance pack 3.0.0, WASM/verifier, table-проекция плана, доки.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…calSites; FFI атомарный маппинг

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts:
#	docs/verification-map.md
…nifest (#292)

package capability ≠ compiled invocation plan ≠ result evidence:

- NumericalDecisionV1 атомарен: Determinate{sealed BitExact evidence} |
  Compatibility{registered release_id + LegacyPlatformDependentV1} |
  Indeterminate; незаконные комбинации непредставимы типами; dead
  classify_at_least_v1/AtLeastDecisionV1/DecisionGuaranteeV1 удалены
  (compile_fail doc-тесты фиксируют миграцию);
- RoleSpec::Glow несёт typed NumericalExecutionModeV1; прежние ключи
  stable-v1|legacy-platform-dependent-v1 — только boundary-адаптер;
- numerical_plan.rs: invocation identity (opaque node bytes + site +
  локальный ordinal), canonical derived-проекция + FNV drift-checksum;
  NamedRoleTable::numerical_plan_v1() — биекция с Glow-ролями;
- capability manifest по канону #289 (length-prefixed preimage, домены
  labcolors.numerical-*); conformance pack 3.0.0: numericalCapabilities
  вместо numericalSites (vectors нетронуты, packDigest прежний);
- WASM/FFI: атомарный маппинг без cross-product реконструкции; wire-байты
  и JSON прежние (golden/npm 106/106 без regen); additive-поверхность
  numericalCapabilityManifest() в WASM/npm; verifier с независимым JS
  FNV-оракулом; release-manifest schema 2 + read-back в publish.yml.

Публичные цвета/fingerprint/CSS/adaptive trace не изменились.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Encoding — внешний versioned контракт (adapter-оракулы переигрывают его
независимо): эквивалентный мутант потери mode-tag (компенсируемый
release-ключом) обязан умирать замороженным вектором, а не выживать.
Мутационные пробы: P1 (mode-tag) убит этим тестом; P2 (глобальный ordinal)
и P3 (потеря release в манифесте) убиты существующими.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 21 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: ASSERTIVE

Plan: Pro Plus

Run ID: 4d2b533a-dd43-4676-a292-8331f71b58e5

📥 Commits

Reviewing files that changed from the base of the PR and between 6285b23 and 3ae4a15.

📒 Files selected for processing (6)
  • bindings/swift/Tests/LabColorsConformanceTests/ConformanceTests.swift
  • crates/labcolors-core/src/glow.rs
  • crates/labcolors-core/src/numerical_plan.rs
  • crates/labcolors-core/src/numerics.rs
  • docs/verification-map.md
  • packages/colors/README.md

Walkthrough

PR переводит численные решения Glow на typed execution modes и атомарные outcomes, добавляет канонический numerical plan и capability manifest, обновляет Rust/WASM/FFI/npm/conformance/release-контракты, проверки checksum, документацию и тесты.

Changes

Численные контракты и план исполнения

Layer / File(s) Summary
Core-контракты и numerical plan
crates/labcolors-core/src/numerics.rs, crates/labcolors-core/src/numerical_plan.rs, crates/labcolors-core/src/lib.rs, .cargo/mutants.toml
Добавлены typed execution modes, sealed evidence, capability manifest и канонический компилятор numerical plan с identity, ordinal и checksum.
Glow execution mode и результаты
crates/labcolors-core/src/glow.rs, crates/labcolors-core/src/semantic.rs, crates/labcolors-core/src/config.rs, crates/labcolors-core/src/agnostic_gates.rs, crates/labcolors-core/tests/property_invariants.rs, crates/labcolors-core/benches/glow_alpha.rs
Glow resolver и role tables используют NumericalExecutionModeV1, возвращают атомарные outcomes и проверяют plan-инварианты.

Boundary-манифесты и release-проверки

Layer / File(s) Summary
FFI, WASM и npm projections
crates/labcolors-ffi/src/lib.rs, crates/labcolors-wasm/src/*, crates/labcolors-wasm/tests/*, packages/colors/*
Boundary-контракты переведены на GlowDecisionOutcomeV1; добавлен экспорт typed numerical capability manifest и соответствующие тесты.
Conformance pack и release verification
crates/labcolors-conformance/*, conformance/*, scripts/verify-package-release.mjs, .github/workflows/publish.yml, packages/colors/test/release-contract.test.mjs
Pack обновлён до 3.0.0 с numericalCapabilities; release manifest использует schema v2 и независимо проверяет capability checksum.
Независимая Swift-проверка
bindings/swift/Tests/LabColorsConformanceTests/ConformanceTests.swift
Swift-тесты декодируют capability manifest и пересчитывают его canonical checksum.

Документация контрактов

Layer / File(s) Summary
Документация и migration notes
CHANGELOG.md, README.md, docs/decisions/*, docs/migrations/*, docs/verification-map.md, packages/colors/README.md, conformance/README.md
Документация описывает breaking Rust API, typed Glow outcomes, capability manifest и переход на conformance pack 3.0.0.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related issues

  • Labpics-Team/lab-colors issue 289 — охватывает тот же redesign capability manifest, numerical plan, typed modes и result evidence.

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Изменения закрывают требования #292: typed Glow mode, immutable plan, atomic results, capability manifest, тесты и сохранение wire-контрактов.
Out of Scope Changes check ✅ Passed Новых несвязанных изменений не видно; правки в доках, тестах и релизных скриптах поддерживают заявленные цели PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Заголовок точно отражает основные изменения: атомарные исходы, план выполнения и capability manifest.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/numerical-plan-evidence-292

Comment @coderabbitai help to get the list of available commands.

@lemone112

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 12, 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.

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

🤖 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 `@bindings/swift/Tests/LabColorsConformanceTests/ConformanceTests.swift`:
- Around line 125-129: Update testCapabilityManifestChecksumRecomputes to assert
that manifest.schemaVersion equals 1 before validating the V1
capability-manifest fields, ensuring newer schema versions cannot pass this
conformance test with a recomputed checksum.

In `@crates/labcolors-core/src/glow.rs`:
- Around line 204-211: Обновите from_execution_mode, чтобы ExplicitCompatibility
сопоставлялся с конкретным release и site Glow, а не с шаблоном { .. }. Для
несовместимых или неизвестных release сохраните явную обработку, чтобы
добавление нового идентификатора требовало отдельной ветки и решения
компилятора.

In `@crates/labcolors-core/src/numerical_plan.rs`:
- Around line 249-255: Replace the sort_unstable_by comparator in the invocation
ordering flow with sort_by_cached_key, using each invocation’s canonical_bytes()
as the cached key. Remove the redundant site_id.key() secondary comparison,
while preserving canonical identity-byte ordering.
- Around line 402-408: Rename unregistered_release_is_a_typed_compile_error to
accurately describe the registered-release happy path, and update its comments
to explicitly mark the UnregisteredCompatibilityRelease branch as vacuous until
another release or site can be constructed. Keep the existing compatibility
assertion unchanged and do not claim coverage of the negative path.

In `@crates/labcolors-core/src/numerics.rs`:
- Around line 718-749: Усилить registry-guard тесты в
bit_exact_mint_is_refused_without_declared_capability: добавить отрицательную
fixture-запись без BitExact и проверить, что mint_bit_exact_evidence отклоняет
её, сохранив успешный сценарий для GlowTargetOrMaximumV1. Расширить
uniqueness-проверку всех checksum-списков registry, а не только
row.stable_outcomes, чтобы каждый set-поле проверялось на дубликаты.
- Around line 565-669: Сначала добавьте compile-fail тест, подтверждающий, что
внешний код не может повторно привязать скопированное evidence к произвольным
value и site_id либо напрямую создать Compatibility. Затем измените
NumericalDecisionV1: замените открытые поля вариантов на непрозрачные структуры
с приватными полями, а создание Determinate и Compatibility оставьте только
через core-owned конструкторы, валидирующие registry и фактически исполненный
release; сохраните существующие типы evidence и provenance.

In `@crates/labcolors-core/src/semantic.rs`:
- Around line 2361-2454: Вынеси локальное замыкание assemble из ветки
RoleSpec::Glow в отдельный приватный метод или функцию, принимающую GlowSolve,
GlowDecisionOutcomeV1, источник tint и фоновые данные. Сохрани без изменений
сборку слоёв, измерение core, заполнение GlowResolved и преобразование ошибок в
Resolved::Unreachable; вызов из solve_screen_alpha_for_dj должен использовать
новый выделенный символ для обоих determinate-исходов.

In `@docs/verification-map.md`:
- Line 103: Insert a blank line immediately before the “Численные решения —
`numerics.rs`, `numerical_plan.rs` (`#292`)” Markdown heading in the
documentation.

In `@packages/colors/README.md`:
- Around line 173-178: Переведите пояснительный текст в README на русский:
замените обычные термины union, stable/legacy profile, guarantee, selection
diagnostic, status, compatibility-результат, determinate и Outward interval
русскими формулировками, сохранив точные wire-значения вроде `kind: "glow"` и
`decisionGuarantee: { kind: "legacy-platform-dependent-v1" }` в обратных
кавычках.
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: 3d4db182-ef02-4252-bf7d-28dd230386d4

📥 Commits

Reviewing files that changed from the base of the PR and between 9ac7785 and 6285b23.

📒 Files selected for processing (33)
  • .cargo/mutants.toml
  • .github/workflows/publish.yml
  • CHANGELOG.md
  • README.md
  • bindings/swift/Tests/LabColorsConformanceTests/ConformanceTests.swift
  • conformance/README.md
  • conformance/vectors/manifest.json
  • crates/labcolors-conformance/src/lib.rs
  • crates/labcolors-conformance/tests/reference_runner.rs
  • crates/labcolors-core/benches/glow_alpha.rs
  • crates/labcolors-core/src/agnostic_gates.rs
  • crates/labcolors-core/src/config.rs
  • crates/labcolors-core/src/glow.rs
  • crates/labcolors-core/src/lib.rs
  • crates/labcolors-core/src/numerical_plan.rs
  • crates/labcolors-core/src/numerics.rs
  • crates/labcolors-core/src/semantic.rs
  • crates/labcolors-core/tests/property_invariants.rs
  • crates/labcolors-ffi/src/lib.rs
  • crates/labcolors-wasm/src/dto.rs
  • crates/labcolors-wasm/src/engine.rs
  • crates/labcolors-wasm/src/lib.rs
  • crates/labcolors-wasm/src/projection.rs
  • crates/labcolors-wasm/tests/wasm_parity.rs
  • docs/decisions/0004-finite-alpha-glow-reference.md
  • docs/migrations/exact-alpha-glow.md
  • docs/verification-map.md
  • packages/colors/README.md
  • packages/colors/index.d.ts
  • packages/colors/index.js
  • packages/colors/test/capability-manifest.test.mjs
  • packages/colors/test/release-contract.test.mjs
  • scripts/verify-package-release.mjs

Comment on lines +204 to +211
/// Обратная проекция generic mode в boundary-ключ (adapter-сторона).
pub fn from_execution_mode(mode: NumericalExecutionModeV1) -> Self {
match mode {
NumericalExecutionModeV1::StableOnly => Self::StableV1,
NumericalExecutionModeV1::ExplicitCompatibility { .. } => {
Self::LegacyPlatformDependentV1
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Не стирайте identity compatibility release в обратном адаптере.

Шаблон { .. } молча спроецирует любой будущий release, включая release другого site, в legacy-профиль Glow. Сопоставьте конкретный Glow release, чтобы добавление нового ID потребовало явного решения компилятора.

Предлагаемое исправление
 pub fn from_execution_mode(mode: NumericalExecutionModeV1) -> Self {
     match mode {
         NumericalExecutionModeV1::StableOnly => Self::StableV1,
-        NumericalExecutionModeV1::ExplicitCompatibility { .. } => {
+        NumericalExecutionModeV1::ExplicitCompatibility {
+            release_id:
+                NumericalCompatibilityReleaseIdV1::GlowCam16UcsJPrimeTargetOrMaxV1,
+        } => {
             Self::LegacyPlatformDependentV1
         }
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// Обратная проекция generic mode в boundary-ключ (adapter-сторона).
pub fn from_execution_mode(mode: NumericalExecutionModeV1) -> Self {
match mode {
NumericalExecutionModeV1::StableOnly => Self::StableV1,
NumericalExecutionModeV1::ExplicitCompatibility { .. } => {
Self::LegacyPlatformDependentV1
}
}
/// Обратная проекция generic mode в boundary-ключ (adapter-сторона).
pub fn from_execution_mode(mode: NumericalExecutionModeV1) -> Self {
match mode {
NumericalExecutionModeV1::StableOnly => Self::StableV1,
NumericalExecutionModeV1::ExplicitCompatibility {
release_id:
NumericalCompatibilityReleaseIdV1::GlowCam16UcsJPrimeTargetOrMaxV1,
} => {
Self::LegacyPlatformDependentV1
}
}
🤖 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 `@crates/labcolors-core/src/glow.rs` around lines 204 - 211, Обновите
from_execution_mode, чтобы ExplicitCompatibility сопоставлялся с конкретным
release и site Glow, а не с шаблоном { .. }. Для несовместимых или неизвестных
release сохраните явную обработку, чтобы добавление нового идентификатора
требовало отдельной ветки и решения компилятора.

Comment thread crates/labcolors-core/src/numerical_plan.rs Outdated
Comment thread crates/labcolors-core/src/numerical_plan.rs Outdated
Comment on lines +565 to +669
/// Provenance-класс текущего нехарактеризованного legacy-пути. Тип-уровневый
/// маркер: `Compatibility` физически не может нести stable/exact provenance.
/// `PlatformCharacterized` не существует до immutable attestation registry (#258).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LegacyPlatformDependentV1;

impl LegacyPlatformDependentV1 {
/// Стабильный wire key класса.
pub fn key(self) -> &'static str {
"legacy-platform-dependent-v1"
}
}

/// Печать evidence: тип публичен (входит в публичный enum-вариант), но его
/// приватное поле делает конструирование возможным только внутри модуля —
/// внешний код может лишь матчить вариант через `..`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EvidenceSeal {
_private: (),
}

/// Запечатанное evidence determinate-решения. В V1 минтится только реально
/// admitted `BitExact`; bounded/canonical-finite варианты появятся вместе с
/// зарегистрированным verifier и bound/artifact identity (#284/#291) —
/// фиктивные IDs запрещены.
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum DecisionGuaranteeV1 {
/// Решение следует только из exact integer/rational state.
BitExact,
/// Решение следует из непересекающегося outward-интервала.
OutwardIntervalV1(OutwardIntervalV1),
/// Явно выбранный прежний platform/libm-dependent путь.
LegacyPlatformDependentV1,
pub enum NumericalDecisionEvidenceV1 {
/// Решение следует из точного конечного состояния объявленного
/// reference-профиля.
BitExact {
/// Профиль, в чьём точном домене доказан результат.
reference_profile_id: ReferenceProfileIdV1,
/// Печать: внешняя конструкция невозможна (тип поля приватен).
_seal: EvidenceSeal,
},
}

impl DecisionGuaranteeV1 {
/// Стабильный wire key.
pub fn key(self) -> &'static str {
impl NumericalDecisionEvidenceV1 {
/// Стабильный wire key класса evidence.
pub fn class_key(&self) -> &'static str {
match self {
Self::BitExact => "bit-exact",
Self::OutwardIntervalV1(_) => "outward-interval-v1",
Self::LegacyPlatformDependentV1 => "legacy-platform-dependent-v1",
Self::BitExact { .. } => "bit-exact",
}
}
}

/// Доказанный interval, если именно он является certificate решения.
pub fn interval(self) -> Option<OutwardIntervalV1> {
match self {
Self::OutwardIntervalV1(interval) => Some(interval),
Self::BitExact | Self::LegacyPlatformDependentV1 => None,
}
/// Registry-owned минт BitExact-evidence: допустим только для site, чья
/// capability-строка объявляет класс BitExact.
///
/// # Errors
///
/// Site не зарегистрирован либо не объявляет BitExact.
pub(crate) fn mint_bit_exact_evidence(
site_id: NumericalSiteIdV1,
reference_profile_id: ReferenceProfileIdV1,
) -> Result<NumericalDecisionEvidenceV1, String> {
let row = registry_row(site_id)
.ok_or_else(|| format!("site {} отсутствует в registry V1", site_id.key()))?;
if !row
.evidence_classes
.contains(&NumericalEvidenceClassV1::BitExact)
{
return Err(format!(
"site {} не объявляет evidence class bit-exact",
site_id.key()
));
}
Ok(NumericalDecisionEvidenceV1::BitExact {
reference_profile_id,
_seal: EvidenceSeal { _private: () },
})
}

/// Semantic result с явным numerical proof class.
/// Атомарный терминальный результат численного решения.
///
/// Три законных класса; их смешение непредставимо типами:
///
/// * `Determinate` — доказанное решение с запечатанным evidence;
/// * `Compatibility` — явный прежний алгоритм (registered release) c
/// provenance-классом `LegacyPlatformDependentV1`; не determinate evidence
/// и не конвертируется в BitExact/Bounded/Proven*;
/// * `Indeterminate` — stable branch честно не выбран.
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum NumericalDecisionV1<T> {
/// Решение принято под указанной гарантией.
/// Решение принято под запечатанным evidence.
Determinate {
/// Зарегистрированный site.
site_id: NumericalSiteIdV1,
/// Предметный результат.
value: T,
/// Запечатанное registry-owned evidence.
evidence: NumericalDecisionEvidenceV1,
},
/// Явно выбранный зарегистрированный прежний алгоритм.
Compatibility {
/// Зарегистрированный site.
site_id: NumericalSiteIdV1,
/// Registered release, реально исполнивший invocation.
release_id: NumericalCompatibilityReleaseIdV1,
/// Предметный результат.
value: T,
/// Почему branch считается доказанным в объявленном профиле.
guarantee: DecisionGuaranteeV1,
/// Класс происхождения (не заменяет release identity).
provenance: LegacyPlatformDependentV1,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Запретите внешнюю реконструкцию атомарных исходов.

Приватная печать блокирует только создание нового BitExact, но evidence имеет Copy: клиент может скопировать его из законного результата и собрать новый Determinate с произвольными value и site_id. Compatibility вообще конструируется напрямую без доказательства исполнения release. Поэтому незаконные комбинации остаются представимыми.

Сначала добавьте compile-fail тест на повторную привязку evidence, затем перенесите поля вариантов в непрозрачные структуры с приватными полями и core-only конструкторами.

Рекомендуемая форма API
-pub enum NumericalDecisionV1<T> {
-    Determinate { site_id: NumericalSiteIdV1, value: T, evidence: NumericalDecisionEvidenceV1 },
-    Compatibility { site_id: NumericalSiteIdV1, release_id: NumericalCompatibilityReleaseIdV1, value: T, provenance: LegacyPlatformDependentV1 },
-    Indeterminate { site_id: NumericalSiteIdV1, evidence: NumericalIndeterminacyV1 },
-}
+pub enum NumericalDecisionV1<T> {
+    Determinate(DeterminateDecisionV1<T>),
+    Compatibility(CompatibilityDecisionV1<T>),
+    Indeterminate(IndeterminateDecisionV1),
+}
+
+pub struct DeterminateDecisionV1<T> {
+    site_id: NumericalSiteIdV1,
+    value: T,
+    evidence: NumericalDecisionEvidenceV1,
+}

As per coding guidelines: «Для дефекта сначала создать тест, проходящий через сломанный путь и падающий по правильной причине, затем реализовать минимальный полный срез».

🤖 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 `@crates/labcolors-core/src/numerics.rs` around lines 565 - 669, Сначала
добавьте compile-fail тест, подтверждающий, что внешний код не может повторно
привязать скопированное evidence к произвольным value и site_id либо напрямую
создать Compatibility. Затем измените NumericalDecisionV1: замените открытые
поля вариантов на непрозрачные структуры с приватными полями, а создание
Determinate и Compatibility оставьте только через core-owned конструкторы,
валидирующие registry и фактически исполненный release; сохраните существующие
типы evidence и provenance.

Source: Coding guidelines

Comment thread crates/labcolors-core/src/numerics.rs Outdated
Comment on lines +2361 to +2454
RoleSpec::Glow { tint, step, mode } => {
// Свечение: halo = якорь источника по теме; core — пересвет;
// интенсивность решается под контрактную ступень на фоне резолва.
// Typed execution mode исполняется ПРЯМО из compiled spec (#292):
// никакого plan lookup или string policy selection в hot path.
let halo_hex = crate::spaces::srgb::hex_from_srgb_encoded(tint.for_vc(vc));
let bg_hex =
crate::spaces::srgb::hex_from_srgb_encoded(quantise_encoded(bg.encoded_display()));
// Общая сборка полного Glow-результата из решённого состояния —
// одна для обоих атомарных законных исходов.
let assemble = |g: &crate::glow::GlowSolve,
outcome: crate::glow::GlowDecisionOutcomeV1|
-> Resolved {
let (core_hex, halo_hex) = match crate::glow::glow_layers_from_source(&halo_hex, vc)
{
Ok(pair) => pair,
Err(e) => {
return Resolved::Unreachable(Unreachable::InternalInvariant(format!(
"generated Glow layer recipe was rejected: {e}"
)));
}
};
let core_measurement = match crate::glow::measure_screen_layer_at_alpha(
&core_hex,
&bg_hex,
g.alpha(),
vc,
) {
Ok(measurement) => measurement,
Err(e) => {
return Resolved::Unreachable(Unreachable::InternalInvariant(format!(
"generated Glow core measurement was rejected: {e}"
)));
}
};
Resolved::Glow(GlowResolved {
core_hex,
halo_hex,
alpha: g.alpha(),
alpha_css: g.alpha_css().to_string(),
target_dj: g.target_dj(),
halo_composite_hex: g.composite_hex().to_string(),
halo_achieved_dj: g.achieved_dj(),
core_composite_hex: core_measurement.composite_hex,
core_achieved_dj: core_measurement.achieved_dj,
target_status: g.status(),
layer_recipe_profile:
crate::glow::GlowLayerRecipeProfileV1::Cam16JPrimeOklabCuspV1,
appearance_diagnostic_profile:
crate::glow::GlowDiagnosticProfileV1::Cam16UcsJPrimeLi2017V1,
selection_diagnostic_profile: g.selection_diagnostic_profile(),
decision_outcome: outcome,
halo_composite_certificate: g.composite_certificate().clone(),
core_composite_certificate: core_measurement.certificate,
})
};
return match crate::glow::solve_screen_alpha_for_dj(
&halo_hex,
&bg_hex,
step.target_dj(),
decision_profile,
mode,
vc,
) {
Ok(crate::numerics::NumericalDecisionV1::Indeterminate { site_id, evidence }) => {
Resolved::GlowIndeterminate(GlowIndeterminateResolved {
source_hex: halo_hex,
target_dj: step.target_dj(),
decision_profile,
decision_profile: crate::glow::GlowDecisionProfileV1::from_execution_mode(
mode,
),
site_id,
evidence,
})
}
Ok(crate::numerics::NumericalDecisionV1::Determinate {
value: g,
guarantee,
}) => {
let (core_hex, halo_hex) =
match crate::glow::glow_layers_from_source(&halo_hex, vc) {
Ok(pair) => pair,
Err(e) => {
return Resolved::Unreachable(Unreachable::InternalInvariant(
format!("generated Glow layer recipe was rejected: {e}"),
));
}
};
let core_measurement = match crate::glow::measure_screen_layer_at_alpha(
&core_hex,
&bg_hex,
g.alpha(),
vc,
) {
Ok(measurement) => measurement,
Err(e) => {
return Resolved::Unreachable(Unreachable::InternalInvariant(format!(
"generated Glow core measurement was rejected: {e}"
)));
}
};
Resolved::Glow(GlowResolved {
core_hex,
halo_hex,
alpha: g.alpha(),
alpha_css: g.alpha_css().to_string(),
target_dj: g.target_dj(),
halo_composite_hex: g.composite_hex().to_string(),
halo_achieved_dj: g.achieved_dj(),
core_composite_hex: core_measurement.composite_hex,
core_achieved_dj: core_measurement.achieved_dj,
target_status: g.status(),
layer_recipe_profile:
crate::glow::GlowLayerRecipeProfileV1::Cam16JPrimeOklabCuspV1,
appearance_diagnostic_profile:
crate::glow::GlowDiagnosticProfileV1::Cam16UcsJPrimeLi2017V1,
selection_diagnostic_profile: g.selection_diagnostic_profile(),
decision_profile,
decision_guarantee: guarantee,
halo_composite_certificate: g.composite_certificate().clone(),
core_composite_certificate: core_measurement.certificate,
})
}
evidence,
..
}) => assemble(
&g,
crate::glow::GlowDecisionOutcomeV1::StableExactNoop { evidence },
),
Ok(crate::numerics::NumericalDecisionV1::Compatibility {
value: g,
release_id,
provenance,
..
}) => assemble(
&g,
crate::glow::GlowDecisionOutcomeV1::Compatibility {
release_id,
provenance,
},
),

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 | 🔵 Trivial | 💤 Low value

Замыкание assemble можно выделить в отдельный приватный метод.

Логика довольно объёмная (сборка core/halo слоёв, измерение композита, конструирование GlowResolved) и живёт как локальное замыкание внутри match-ветки. Поведение корректно (поля GlowResolved собраны верно для обоих атомарных исходов, ошибки не паникуют, а превращаются в Resolved::Unreachable), но вынесение в приватную функцию упростило бы читаемость и позволило бы точечно протестировать сборку без похода через solve_screen_alpha_for_dj.

🤖 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 `@crates/labcolors-core/src/semantic.rs` around lines 2361 - 2454, Вынеси
локальное замыкание assemble из ветки RoleSpec::Glow в отдельный приватный метод
или функцию, принимающую GlowSolve, GlowDecisionOutcomeV1, источник tint и
фоновые данные. Сохрани без изменений сборку слоёв, измерение core, заполнение
GlowResolved и преобразование ошибок в Resolved::Unreachable; вызов из
solve_screen_alpha_for_dj должен использовать новый выделенный символ для обоих
determinate-исходов.

Comment thread docs/verification-map.md
Comment thread packages/colors/README.md Outdated
- Swift-оракул пинует capability schemaVersion == 1;
- from_execution_mode матчит точный Glow-release (без стирания identity);
- план: sort_by_cached_key (ключ один раз), тайбрейкер удалён как избыточный;
- честное имя вакуумного теста незарегистрированного release (+ маркер #291);
- mint-гард тестируем на row-уровне (отказная ветвь исполняется), uniqueness
  покрывает все checksum-списки;
- MD022 в verification-map; русификация терминов в packages/colors/README.

Отклонено с аргументацией: полная непрозрачность вариантов NumericalDecisionV1
(heavy-lift вне bounded slice: исходы текут только ИЗ core, ядро их не
принимает на вход; consumer-verifier — #284/#291) и вынос assemble-замыкания
(low value по оценке самого ревьюера).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@lemone112

Copy link
Copy Markdown
Collaborator Author

@coderabbitai Обработаны все 9 замечаний (head 3ae4a15):

Исправлено (7): Swift-пин schemaVersion == 1; точный Glow-release в from_execution_mode (identity не стирается); sort_by_cached_key + удалён избыточный тайбрейкер; честное имя вакуумного теста (+ маркер настоящего негативного кейса при втором release, #291); mint-гард вынесен на row-уровень — отказная ветвь исполняется синтетической строкой; uniqueness покрывает все шесть checksum-списков; MD022; русификация терминов в packages/colors/README.

Отклонено с основанием (2):

  1. Непрозрачные структуры для всех вариантов NumericalDecisionV1 — согласен с направлением, но это heavy-lift за границей bounded slice: исходы текут только ИЗ core (ядро не принимает NumericalDecisionV1 на вход, клиентская фабрикация не влияет на resolve), незаконная комбинация stable×legacy типами уже непредставима — что и требует acceptance ARCH/NUMERICS: Glow per-invocation plan и Compatibility result #292. Полное запечатывание вместе с consumer-verifier — BUG/A11Y: ввести доказуемый versioned WCAG 2.2 sRGB8 evaluator #284/CORRECTNESS: audit every branch-sensitive numerical site beyond migrated Glow V1 #291. Предложенный первый шаг (compile-fail на re-binding) невыполним: копирование Copy-evidence компилируется по определению.
  2. Вынос assemble-замыкания — косметика с пометкой low value самого ревью; захват 4 локалов сделал бы сигнатуру шумнее тела.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Tip

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

@lemone112 Спасибо за подробный отчёт по всем 9 замечаниям на 3ae4a15.

По исправленным (7) — принято, изменения выглядят обоснованными и точечными.

По отклонённым (2):

  1. Непрозрачные структуры для всех вариантов NumericalDecisionV1 — согласен с обоснованием. Аргумент про Copy-семантику evidence и невозможность compile-fail на ре-биндинг корректен: если NumericalDecisionEvidenceV1 реализует Copy, никакой borrow-checker трюк не запретит копирование значения после его "печати" — это фундаментальное ограничение, а не недосмотр реализации. Раз потоки решений строго однонаправленные (только из core, без приёма на вход), риск от текущей неполной изоляции ограничен. Полное запечатывание в рамках #284/CORRECTNESS: audit every branch-sensitive numerical site beyond migrated Glow V1 #291 — разумный план для отдельного PR, где можно спроектировать границу без спешки.
  2. Вынос assemble-замыкания — согласен, это чисто косметическое предложение с низкой ценностью; оставлять как есть — нормально.

Если понадобится, могу открыть follow-up issue со ссылкой на #284/#291 для трекинга полного запечатывания evidence, но раз вы уже сослались на существующие issue-номера, полагаю трекинг уже настроен.

(๑˃̵ᴗ˂̵)و

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.

ARCH/NUMERICS: Glow per-invocation plan и Compatibility result

1 participant