Skip to content

Core: ввести типизированные направленные отношения - #489

Merged
lemone112 merged 7 commits into
mainfrom
agent/v5a-core
Jul 28, 2026
Merged

Core: ввести типизированные направленные отношения#489
lemone112 merged 7 commits into
mainfrom
agent/v5a-core

Conversation

@lemone112

@lemone112 lemone112 commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Зачем

V5a заменяет специальные парные/ролевые ветви одной типизированной алгеброй физических отношений. Core видит направление и физический уровень связи, но не клиентскую семантику имён.

Что изменено

  • канонический DirectedRelationV1<T>: reference и непустое уникальное множество candidates;
  • четыре общие формы Program: intrinsic/visible unary и intrinsic/visible directed relation;
  • единый evaluator registry без topology-specific solver paths;
  • полное evidence для каждого constraint × case × candidate, без last-writer-wins;
  • единый preallocated relation-evidence protocol без аллокаций в candidate loop;
  • атомарная identity schema V6 без V5 aliases и compatibility paths;
  • checked ID remap, отвергающий неинъективные отображения;
  • общие invariant/vocabulary gates против возврата специальных ролей;
  • hostile fixtures закрывают relation remap, OR-агрегацию, полный hard-count и отделение report-only.

Границы

PR не вводит family generator, selection policy, sentiment, cleanliness auto или публичный Program API. Это общий физический фундамент для V5b/V5c.

Доказательства exact head

Head: d2a2dfe0716fc9f448c0c69818e85e19181a65eb.

  • локально весь workspace и doctests — PASS; Core: 931 passed, 0 failed, 6 ignored;
  • clean-set product receipt: PASS, 31 hostile verifier tests;
  • point-support receipt/source binding: PASS;
  • WASM release package verification: PASS;
  • независимый architecture/API/numerical/performance review: PASS после исправления трёх доказанных test-vacuum;
  • targeted mutation: 178 generated, 88 viable caught, 90 unviable, 0 missed, 0 timeout;
  • три отдельно воспроизведённых surviving mutants: 0/3 survivors;
  • CI run 30382348608: MSRV, fmt/clippy, docs, tests, audit, WASM/headless/size и Node 22 — PASS;
  • native run 30382348449: Swift Linux conformance — PASS; macOS paid runner штатно SKIPPED policy;
  • свежий incremental CodeRabbit по 8924bb2..d2a2dfe: No actionable comments, exact status SUCCESS.

Merge допускается: exact head, CI, mutation и оба review-контура зелёные.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Добавлены directed relation constraints и intrinsic-unary проверки, специализированные Program Session body/evidence и typed compile errors. Content identity переведён на V6, evaluation arena расширена relation members, а тесты, source inventories и контрольные хэши обновлены.

Changes

Relation constraints и Program Session

Layer / File(s) Summary
Канонические relations и exact-профили
crates/labcolors-core/src/relation.rs, crates/labcolors-core/src/constraints/*, crates/labcolors-core/src/observation.rs
Добавлены валидируемые directed relations, exact sRGB8 intrinsic/relation profiles и типизированный непустой набор сценариев.
Program IR и evidence API
crates/labcolors-core/src/program.rs, crates/labcolors-core/src/program_session.rs
Добавлены специализированные constraint bodies, Draft-конструкторы, typed compile errors, subject-варианты и intrinsic/relation evidence.
Компиляция и runtime evaluation
crates/labcolors-core/src/program_session.rs
Компилятор обрабатывает visible/intrinsic unary и relation endpoints, а evaluation arena хранит relation-member evidence и предоставляет его через report API.
Content identity V6
crates/labcolors-core/src/program_identity.rs, crates/labcolors-core/src/program.rs
Графовая сериализация, release tags, leaf domain и публичные content identity обновлены до V6 с поддержкой новых constraint families.
Миграция тестов и контрактов
crates/labcolors-core/src/*tests.rs, crates/labcolors-core/contracts/*, scripts/verify_point_support_surplus.py
Тестовые сценарии переведены на VisibleUnary и новые relation API; обновлены golden identities, source inventories и закреплённые SHA-256 значения.

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

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 49.09% 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
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Заголовок кратко и точно отражает основную часть изменений: ввод типизированных направленных отношений в Core.
✨ 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 agent/v5a-core

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

@lemone112

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
crates/labcolors-core/src/generic_boundary_tests.rs (1)

1312-1322: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Запрет ProgramSessionEvaluationError::VisibleUnary не защищает ни от чего.

Остальные записи в этом forbidden-списке — реальные символы прежнего eager-LCS пути. У ProgramSessionEvaluationError варианта VisibleUnary не существует ни в старом, ни в новом коде, поэтому assert выполняется тривиально. Если цель — запретить возврат unary-специфичной ошибки из evaluation-пути, стоит закрепить реально существующий анти-дрейф маркер; иначе строку лучше убрать, чтобы не создавать иллюзию покрытия.

Проверьте, какие варианты действительно объявлены в enum:

#!/bin/bash
ast-grep run --pattern $'pub enum ProgramSessionEvaluationError<$_> {
  $$$
}' --lang rust crates/labcolors-core/src/program_session.rs
rg -nP 'ProgramSessionEvaluationError::\w+' crates/labcolors-core/src --no-heading | sort -u | head -50
🤖 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/generic_boundary_tests.rs` around lines 1312 -
1322, Remove the nonexistent ProgramSessionEvaluationError::VisibleUnary entry
from the forbidden list in the generic boundary test. Keep the other eager-LCS
markers unchanged, unless inspection of the declared
ProgramSessionEvaluationError variants identifies an existing unary-specific
evaluation error that should replace it.
crates/labcolors-core/src/program_identity_tests.rs (1)

768-795: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Anti-drift gate покрывает диапазоны, но не «полноту» словаря.

assert_eq!(schema.0, 1..=21) и assert_eq!(schema.1, 1..=27) фиксируют, что fixture исполняет каждый tag/role. Однако при добавлении нового варианта в EdgeRoleV1 тест упадёт лишь на верхней границе, если варианты остаются непрерывными; при добавлении варианта в середину с последующим сдвигом golden-дайджест поймает изменение, но сообщение об ошибке будет неинформативным. Стоит сопоставлять со счётчиком вариантов из program_identity (например, экспортировать EDGE_ROLE_COUNT_V1), чтобы падение сразу указывало на пропущенный role.

🤖 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/program_identity_tests.rs` around lines 768 - 795,
Update complete_program_schema_v6_digest_is_cross_platform_golden to validate
the fixture’s edge-role coverage against an exported EdgeRoleV1 variant count
from program_identity, such as EDGE_ROLE_COUNT_V1, rather than relying only on
the hard-coded 1..=27 range. Preserve the existing schema and digest assertions
while making missing or newly added roles produce an explicit count-based
failure.
🤖 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 `@crates/labcolors-core/src/program_identity.rs`:
- Around line 660-666: Rename the ConstraintGraphBindingContextV1.scenario_group
field and its associated EdgeRoleV1::ScenarioGroup usage to clearly identify the
bound observation-group vertex, updating build_graph and all consumers
consistently; do not leave scenario terminology that could imply a separate
scenario vertex.
- Around line 677-702: In the VisibleUnary arm of the match, replace the
explicit occurrence binding and let _ discard with a .. pattern, while retaining
the invocation binding and existing constraint_color call unchanged.
- Around line 1022-1029: Replace the unchecked color.as_slice()[0] access in the
vertex_tags construction with typed handling for empty colors: return
ProgramCompileError::InternalInvariant when a color has no bytes, while
preserving tag collection, sorting, and deduplication for non-empty colors.

In `@crates/labcolors-core/src/program_mixed_evaluator_tests.rs`:
- Around line 836-845: Update the checksum handling in the
ConstraintSubjectV1::IntrinsicRelation and ConstraintSubjectV1::VisibleRelation
branches to incorporate their candidates data as well as reference, so differing
candidate sets produce differing checksums. Also address the relation fixture
path around consume_public_assessment so AssessmentV1::Relation is no longer an
unhandled panic, or explicitly mark these branches as unsupported stubs until a
relation fixture exists.

In `@crates/labcolors-core/src/program_relation_tests.rs`:
- Around line 28-44: Обновите тест
exact_relation_draft_api_requires_an_explicit_physical_level: либо добавьте
assertions, проверяющие состав и физический уровень отношений в draft после
вызовов push_exact_intrinsic_relation_hard и push_exact_visible_relation_hard,
либо переименуйте тест так, чтобы он явно описывал проверяемую type-level
гарантию через TargetIdV1 и OccurrenceIdV1.
- Around line 409-453: Разделите тест
relation_identity_ignores_opaque_names_and_candidate_declaration_order на
независимые проверки: сравните разные offset при одинаковом reverse_candidates
для инвариантности opaque-имён и одинаковый offset при разных reverse_candidates
для порядка candidates. Сохраните существующее сравнение комбинированного случая
только при необходимости, чтобы каждая ось отдельно выявляла регрессии.

In `@crates/labcolors-core/src/program_session.rs`:
- Around line 4126-4296: Extract the shared relation-arena accumulation logic
from the IntrinsicRelation and VisibleRelation branches into a helper near the
surrounding evaluation code, parameterized by candidate count and a closure that
resolves each candidate and returns its evidence plus violation status. Move
capture_start, capacity preflight, evidence accumulation, violation tracking,
NonEmptyRelationMemberSpanV1 construction, and Pass/Violation selection into
that helper; keep each branch responsible only for endpoint resolution,
evidence-member construction, and subject creation.
- Around line 5532-5551: Update the target scan in the constraint-processing
flow around dependency_scratch.scan to validate that dependency_scratch.targets
has the expected length before indexing it alongside program.targets. On
mismatch, return the existing typed InternalInvariant error used by
merge_visible_constraint_coverage; otherwise preserve the current finite-target
detection and SolverDependentVisibleRelationReference behavior.
- Around line 4001-4003: Move the invariant check comparing
constraint.scenario_group with epoch.observation_group.id out of the per-case ×
constraint hot loop and perform it once before iterating cases, validating all
constraints there. Remove the repeated check from the loop while preserving the
existing InternalInvariant error behavior and direct-index execution path.

In `@crates/labcolors-core/src/program.rs`:
- Around line 561-567: Добавьте `///`-документацию ко всем семи новым вариантам
`CompileErrorKindV1` и к каждому новому полю `CompileErrorV1` в указанном
диапазоне, сохранив стиль соседних вариантов и полей. Для
`SolverDependentVisibleRelationReference` явно укажите, что `target` —
finite-цель, из-за которой reference стал solver-зависимым.
- Around line 2462-2477: Уберите оба вызова unreachable! в преобразовании
ProgramConstraintResultV1 в AssessmentV1: relation_members_for может вернуть
None, поэтому проекция не должна паниковать. Измените AssessmentV1 или ближайший
flow построения RelationEvidenceV1 так, чтобы недоступное relation evidence
возвращалось типизированно (предпочтительно передавайте срез при построении
ячейки), сохранив корректные verdict для Pass и Violation.
- Around line 2680-2728: Измените IntrinsicRelationMemberV1 и
VisibleRelationMemberV1 так, чтобы они хранили распакованные ссылки на
соответствующие binding/endpoint и verdict, а не весь
ProgramRelationMemberEvidenceV1. При создании обёрток распакуйте вариант один
раз и передайте эти значения в поля; accessor'ы reference, candidate и verdict
должны возвращать сохранённые значения без повторной проверки и unreachable!().
Сохраните существующее поведение для корректных вариантов.
- Around line 1521-1548: Remove the panic-producing expect calls from
push_exact_intrinsic_relation_hard and push_exact_visible_relation_hard. Prefer
propagating try_map failures as a typed DraftErrorV1 by changing these facade
methods to return Result<&mut Self, DraftErrorV1> and mapping
DirectedRelationErrorV1 accordingly; update their callers to handle the Result
without introducing fallback behavior.

---

Outside diff comments:
In `@crates/labcolors-core/src/generic_boundary_tests.rs`:
- Around line 1312-1322: Remove the nonexistent
ProgramSessionEvaluationError::VisibleUnary entry from the forbidden list in the
generic boundary test. Keep the other eager-LCS markers unchanged, unless
inspection of the declared ProgramSessionEvaluationError variants identifies an
existing unary-specific evaluation error that should replace it.

In `@crates/labcolors-core/src/program_identity_tests.rs`:
- Around line 768-795: Update
complete_program_schema_v6_digest_is_cross_platform_golden to validate the
fixture’s edge-role coverage against an exported EdgeRoleV1 variant count from
program_identity, such as EDGE_ROLE_COUNT_V1, rather than relying only on the
hard-coded 1..=27 range. Preserve the existing schema and digest assertions
while making missing or newly added roles produce an explicit count-based
failure.
🪄 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: 05d1e967-c9bb-42f3-9e23-f491b7c88758

📥 Commits

Reviewing files that changed from the base of the PR and between 432662f and eadfeec.

📒 Files selected for processing (25)
  • crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.json
  • crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.sha256
  • crates/labcolors-core/contracts/point-support-reference-surplus-q55-bps-proof-v1.json
  • crates/labcolors-core/src/appearance.rs
  • crates/labcolors-core/src/constraints/mod.rs
  • crates/labcolors-core/src/constraints/relation.rs
  • crates/labcolors-core/src/generic_boundary_tests.rs
  • crates/labcolors-core/src/lib.rs
  • crates/labcolors-core/src/observation.rs
  • crates/labcolors-core/src/program.rs
  • crates/labcolors-core/src/program/attachment/tests.rs
  • crates/labcolors-core/src/program_api_tests.rs
  • crates/labcolors-core/src/program_boundary_tests.rs
  • crates/labcolors-core/src/program_clean_set_tests.rs
  • crates/labcolors-core/src/program_identity.rs
  • crates/labcolors-core/src/program_identity_tests.rs
  • crates/labcolors-core/src/program_joint_integration_tests.rs
  • crates/labcolors-core/src/program_lcs_integration_tests.rs
  • crates/labcolors-core/src/program_mixed_evaluator_tests.rs
  • crates/labcolors-core/src/program_point_causality_tests.rs
  • crates/labcolors-core/src/program_relation_tests.rs
  • crates/labcolors-core/src/program_session.rs
  • crates/labcolors-core/src/program_session_tests.rs
  • crates/labcolors-core/src/relation.rs
  • scripts/verify_point_support_surplus.py

Comment thread crates/labcolors-core/src/program_identity.rs
Comment thread crates/labcolors-core/src/program_identity.rs
Comment on lines +1022 to +1029
let graph = build_graph(program)?;
let mut vertex_tags = Vec::new();
vertex_tags
.try_reserve_exact(graph.colors.len())
.map_err(|_| ProgramCompileError::ResourceExhausted)?;
vertex_tags.extend(graph.colors.iter().map(|color| color.as_slice()[0]));
vertex_tags.sort_unstable();
vertex_tags.dedup();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Индексация as_slice()[0] — единственный panic-путь в новом helper.

Все остальные шаги функции возвращают типизированную ошибку (ResourceExhausted), а извлечение tag полагается на непустоту цвета. Инвариант «VertexColorV1::new всегда пишет tag первым байтом» здесь не выражен: либо зафиксируйте его комментарием «почему», либо верните ProgramCompileError::InternalInvariant для пустого цвета.

🛡️ Вариант с типизированным отказом
-    vertex_tags.extend(graph.colors.iter().map(|color| color.as_slice()[0]));
+    for color in &graph.colors {
+        // Первый байт цвета — vertex tag; пустой цвет означает нарушенный
+        // инвариант writer'а, а не допустимую схему.
+        let [tag, ..] = color.as_slice() else {
+            return Err(ProgramCompileError::InternalInvariant);
+        };
+        vertex_tags.push(*tag);
+    }

Согласно coding guidelines: «Новый или изменяемый public path не должен вызывать panic … invalid, unreachable, unsupported и incomplete context должны возвращаться типизированно».

📝 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
let graph = build_graph(program)?;
let mut vertex_tags = Vec::new();
vertex_tags
.try_reserve_exact(graph.colors.len())
.map_err(|_| ProgramCompileError::ResourceExhausted)?;
vertex_tags.extend(graph.colors.iter().map(|color| color.as_slice()[0]));
vertex_tags.sort_unstable();
vertex_tags.dedup();
let graph = build_graph(program)?;
let mut vertex_tags = Vec::new();
vertex_tags
.try_reserve_exact(graph.colors.len())
.map_err(|_| ProgramCompileError::ResourceExhausted)?;
for color in &graph.colors {
// Первый байт цвета — vertex tag; пустой цвет означает нарушенный
// инвариант writer'а, а не допустимую схему.
let [tag, ..] = color.as_slice() else {
return Err(ProgramCompileError::InternalInvariant);
};
vertex_tags.push(*tag);
}
vertex_tags.sort_unstable();
vertex_tags.dedup();
🤖 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/program_identity.rs` around lines 1022 - 1029,
Replace the unchecked color.as_slice()[0] access in the vertex_tags construction
with typed handling for empty colors: return
ProgramCompileError::InternalInvariant when a color has no bytes, while
preserving tag collection, sorting, and deduplication for non-empty colors.

Source: Coding guidelines

Comment on lines +836 to 845
ConstraintSubjectV1::IntrinsicUnary { target } => {
probe.mix(u64::from(target.value()));
}
ConstraintSubjectV1::IntrinsicRelation { reference } => {
probe.mix(u64::from(reference.value()));
}
ConstraintSubjectV1::VisibleRelation { reference, .. } => {
probe.mix(u64::from(reference.value()));
}
}

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 | ⚡ Quick win

Checksum relation-веток игнорирует candidates.

IntrinsicRelation/VisibleRelation подмешивают только reference, поэтому два отношения с разными наборами candidates дадут одинаковый checksum. Одновременно consume_public_assessment (строки 689–691) паникует на AssessmentV1::Relation, то есть ветки в текущей фикстуре недостижимы и не проверены. Либо подмешайте candidates, либо явно зафиксируйте, что ветки — заглушки до появления relation-фикстуры.

♻️ Пример полного подмешивания
-                        ConstraintSubjectV1::VisibleRelation { reference, .. } => {
-                            probe.mix(u64::from(reference.value()));
-                        }
+                        ConstraintSubjectV1::VisibleRelation {
+                            reference,
+                            candidates,
+                        } => {
+                            probe.mix(u64::from(reference.value()));
+                            for candidate in candidates {
+                                probe.mix(u64::from(candidate.value()));
+                            }
+                        }
#!/bin/bash
# Проверяем реальную форму вариантов ConstraintSubjectV1 (наличие поля candidates)
fd -t f 'program' crates/labcolors-core/src --exec ast-grep run --lang rust --pattern 'enum ConstraintSubjectV1 { $$$ }' {} \;
rg -nP -C6 'VisibleRelation\s*\{' crates/labcolors-core/src --type=rust

Also applies to: 880-889

🤖 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/program_mixed_evaluator_tests.rs` around lines 836
- 845, Update the checksum handling in the
ConstraintSubjectV1::IntrinsicRelation and ConstraintSubjectV1::VisibleRelation
branches to incorporate their candidates data as well as reference, so differing
candidate sets produce differing checksums. Also address the relation fixture
path around consume_public_assessment so AssessmentV1::Relation is no longer an
unhandled panic, or explicitly mark these branches as unsupported stubs until a
relation fixture exists.

Comment thread crates/labcolors-core/src/program_relation_tests.rs
Comment thread crates/labcolors-core/src/program_session.rs
Comment thread crates/labcolors-core/src/program.rs
Comment on lines +1521 to +1548
pub(crate) fn push_exact_intrinsic_relation_hard(
&mut self,
id: ConstraintIdV1,
relation: DirectedRelationV1<TargetIdV1>,
) -> &mut Self {
self.inner.push_exact_intrinsic_relation_hard(
id.into_core(),
relation
.try_map(TargetIdV1::into_core)
.expect("facade TargetId is a transparent bijection over Core TargetId"),
);
self
}

/// Добавляет обязательное exact-отношение между final modeled Occurrences.
pub(crate) fn push_exact_visible_relation_hard(
&mut self,
id: ConstraintIdV1,
relation: DirectedRelationV1<OccurrenceIdV1>,
) -> &mut Self {
self.inner.push_exact_visible_relation_hard(
id.into_core(),
relation
.try_map(OccurrenceIdV1::into_core)
.expect("facade OccurrenceId is a transparent bijection over Core OccurrenceId"),
);
self
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

expect на facade-пути Draft противоречит и guideline, и собственному инварианту try_map.

try_map специально спроектирован так, чтобы «даже внутреннему mapper нельзя доверять по комментарию» (relation.rs, строки 64‑67) — и возвращает типизированную DirectedRelationErrorV1. Здесь эта типизированная ошибка немедленно сворачивается в panic на публичном пути построения Draft.

Два варианта без panic:

  1. Хранить в facade DirectedRelationV1<TargetId> / DirectedRelationV1<OccurrenceId> уже в Core-представлении, чтобы remap на этом уровне вообще не требовался;
  2. Либо вернуть Result<&mut Self, DraftErrorV1> и смапить DirectedRelationErrorV1 в типизированный вариант.
♻️ Набросок варианта 2
     pub(crate) fn push_exact_intrinsic_relation_hard(
         &mut self,
         id: ConstraintIdV1,
         relation: DirectedRelationV1<TargetIdV1>,
-    ) -> &mut Self {
-        self.inner.push_exact_intrinsic_relation_hard(
-            id.into_core(),
-            relation
-                .try_map(TargetIdV1::into_core)
-                .expect("facade TargetId is a transparent bijection over Core TargetId"),
-        );
-        self
+    ) -> Result<&mut Self, DraftErrorV1> {
+        let relation = relation
+            .try_map(TargetIdV1::into_core)
+            .map_err(|_| DraftErrorV1::InvalidRelationTopology)?;
+        self.inner
+            .push_exact_intrinsic_relation_hard(id.into_core(), relation);
+        Ok(self)
     }

Как per coding guidelines: «Новый или изменяемый public path не должен вызывать panic и не должен получать plausible fallback; invalid, unreachable, unsupported и incomplete context должны возвращаться типизированно».

🤖 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/program.rs` around lines 1521 - 1548, Remove the
panic-producing expect calls from push_exact_intrinsic_relation_hard and
push_exact_visible_relation_hard. Prefer propagating try_map failures as a typed
DraftErrorV1 by changing these facade methods to return Result<&mut Self,
DraftErrorV1> and mapping DirectedRelationErrorV1 accordingly; update their
callers to handle the Result without introducing fallback behavior.

Source: Coding guidelines

Comment on lines +2462 to +2477
ProgramConstraintResultV1::Pass(ProgramConstraintPassEvidenceV1::Relation(span)) => {
AssessmentV1::Relation(RelationEvidenceV1 {
verdict: VerdictV1::Pass,
members: report
.relation_members_for(*span)
.unwrap_or_else(|| unreachable!("report owns every relation span")),
})
}
ProgramConstraintResultV1::Violation(ProgramConstraintViolationEvidenceV1::Relation(
span,
)) => AssessmentV1::Relation(RelationEvidenceV1 {
verdict: VerdictV1::Violation,
members: report
.relation_members_for(*span)
.unwrap_or_else(|| unreachable!("report owns every relation span")),
}),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

unreachable! при разрешении relation-span — panic на пути проекции evidence.

Тип не связывает span с конкретным report: NonEmptyRelationMemberSpanV1 — обычная пара start/len, а relation_members_for возвращает Option. Здесь это разворачивается в panic вместо типизированного результата.

Минимальный вариант без panic и без изменения публичной формы — добавить в AssessmentV1 явный вариант «evidence недоступно», либо (предпочтительно) сделать span непроецируемым наружу, отдавая срез прямо в момент построения ячейки. Как per coding guidelines: «invalid, unreachable, unsupported и incomplete context должны возвращаться типизированно».

🤖 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/program.rs` around lines 2462 - 2477, Уберите оба
вызова unreachable! в преобразовании ProgramConstraintResultV1 в AssessmentV1:
relation_members_for может вернуть None, поэтому проекция не должна паниковать.
Измените AssessmentV1 или ближайший flow построения RelationEvidenceV1 так,
чтобы недоступное relation evidence возвращалось типизированно (предпочтительно
передавайте срез при построении ячейки), сохранив корректные verdict для Pass и
Violation.

Source: Coding guidelines

Comment on lines +2680 to +2728
#[derive(Clone, Copy)]
pub(crate) struct IntrinsicRelationMemberV1<'a> {
inner: &'a ProgramRelationMemberEvidenceV1,
}

impl IntrinsicRelationMemberV1<'_> {
pub(crate) const fn reference(self) -> IntrinsicPaintBindingV1 {
let Some((reference, _)) = self.inner.intrinsic_bindings() else {
unreachable!()
};
IntrinsicPaintBindingV1::from_core(*reference)
}

pub(crate) const fn candidate(self) -> IntrinsicPaintBindingV1 {
let Some((_, candidate)) = self.inner.intrinsic_bindings() else {
unreachable!()
};
IntrinsicPaintBindingV1::from_core(*candidate)
}

pub(crate) const fn verdict(self) -> VerdictV1 {
project_relation_verdict(self.inner.decision())
}
}

#[derive(Clone, Copy)]
pub(crate) struct VisibleRelationMemberV1<'a> {
inner: &'a ProgramRelationMemberEvidenceV1,
}

impl<'a> VisibleRelationMemberV1<'a> {
pub(crate) const fn reference(self) -> VisibleRelationEndpointV1<'a> {
let Some((reference, _)) = self.inner.visible_bindings() else {
unreachable!()
};
VisibleRelationEndpointV1 { inner: reference }
}

pub(crate) const fn candidate(self) -> VisibleRelationEndpointV1<'a> {
let Some((_, candidate)) = self.inner.visible_bindings() else {
unreachable!()
};
VisibleRelationEndpointV1 { inner: candidate }
}

pub(crate) const fn verdict(self) -> VerdictV1 {
project_relation_verdict(self.inner.decision())
}
}

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 | 🟠 Major | ⚡ Quick win

Голые unreachable!() в accessor'ах member-evidence лучше устранить структурно.

IntrinsicRelationMemberV1 / VisibleRelationMemberV1 хранят весь ProgramRelationMemberEvidenceV1 и заново проверяют вариант в каждом accessor. Поскольку from_core уже разобрал вариант, достаточно сохранить в обёртке сразу распакованные ссылки — тогда panic-ветки исчезают вместе с необходимостью в unreachable!().

♻️ Предлагаемая форма
 #[derive(Clone, Copy)]
 pub(crate) struct IntrinsicRelationMemberV1<'a> {
-    inner: &'a ProgramRelationMemberEvidenceV1,
+    reference: &'a ProgramIntrinsicPaintBindingV1,
+    candidate: &'a ProgramIntrinsicPaintBindingV1,
+    decision: ProgramRelationMemberDecisionV1,
 }
 
 impl IntrinsicRelationMemberV1<'_> {
     pub(crate) const fn reference(self) -> IntrinsicPaintBindingV1 {
-        let Some((reference, _)) = self.inner.intrinsic_bindings() else {
-            unreachable!()
-        };
-        IntrinsicPaintBindingV1::from_core(*reference)
+        IntrinsicPaintBindingV1::from_core(*self.reference)
     }

Как per coding guidelines: «Новый или изменяемый public path не должен вызывать panic».

🤖 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/program.rs` around lines 2680 - 2728, Измените
IntrinsicRelationMemberV1 и VisibleRelationMemberV1 так, чтобы они хранили
распакованные ссылки на соответствующие binding/endpoint и verdict, а не весь
ProgramRelationMemberEvidenceV1. При создании обёрток распакуйте вариант один
раз и передайте эти значения в поля; accessor'ы reference, candidate и verdict
должны возвращать сохранённые значения без повторной проверки и unreachable!().
Сохраните существующее поведение для корректных вариантов.

Source: Coding guidelines

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

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

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/labcolors-core/src/generic_boundary_tests.rs (1)

1464-1475: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Ожидание для VisibleRelation слабее, чем заявленное сообщение теста.

Для VisibleUnary проверяется и извлечение occurrence, и запись индекса, а для VisibleRelation — только факт наличия имени варианта. Сообщение утверждает «remap every constraint», но удаление обхода candidate-endpoint'ов внутри ветки VisibleRelation этот gate не поймает: строка "CompiledProgramConstraintBodyV1::VisibleRelation" останется. Стоит зафиксировать обход reference и candidates явно.

♻️ Предлагаемое усиление
-        "CompiledProgramConstraintBodyV1::VisibleRelation",
+        "CompiledProgramConstraintBodyV1::VisibleRelation { reference, candidates, .. }",
+        "for endpoint in core::iter::once(reference).chain(candidates.iter_mut())",

Точные литералы подберите под фактическую форму compact_constraint_contexts.

🤖 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/generic_boundary_tests.rs` around lines 1464 -
1475, Усильте проверки в тесте вокруг compact_constraint_contexts: вместо
проверки только наличия варианта
CompiledProgramConstraintBodyV1::VisibleRelation зафиксируйте отдельными
уникальными литералами обход reference и candidate endpoints, включая извлечение
occurrence и запись remapped index. Подберите строки по фактической реализации,
чтобы тест обнаруживал удаление этого обхода и действительно проверял remap
каждой constraint.
🤖 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 `@crates/labcolors-core/src/program_joint_integration_tests.rs`:
- Around line 2335-2358: Расширьте тест вокруг финальной проверки
`session.commit(update(1, 0x00))`, добавив constraint с `report_only`, который
возвращает `Violation`. Сохраните ожидаемый `FinalRecheckViolation` и убедитесь,
что его `hard_violation_count` остаётся равным 2, подтверждая подсчёт только
hard-нарушений.

In `@crates/labcolors-core/src/program_relation_tests.rs`:
- Around line 603-608: Разведите числовые идентификаторы в тесте вокруг
`third_candidate` и соответствующего `ConstraintIdV1`: замените переиспользуемое
значение `14` для одной из сущностей на другое уникальное значение, сохранив
корректность проверок координат по индексам и остальную логику теста.

---

Outside diff comments:
In `@crates/labcolors-core/src/generic_boundary_tests.rs`:
- Around line 1464-1475: Усильте проверки в тесте вокруг
compact_constraint_contexts: вместо проверки только наличия варианта
CompiledProgramConstraintBodyV1::VisibleRelation зафиксируйте отдельными
уникальными литералами обход reference и candidate endpoints, включая извлечение
occurrence и запись remapped index. Подберите строки по фактической реализации,
чтобы тест обнаруживал удаление этого обхода и действительно проверял remap
каждой constraint.
🪄 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: f539d4ab-e942-45c1-aea8-fd5344285b21

📥 Commits

Reviewing files that changed from the base of the PR and between eadfeec and 8924bb2.

📒 Files selected for processing (10)
  • crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.json
  • crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.sha256
  • crates/labcolors-core/src/generic_boundary_tests.rs
  • crates/labcolors-core/src/program.rs
  • crates/labcolors-core/src/program_identity.rs
  • crates/labcolors-core/src/program_identity_tests.rs
  • crates/labcolors-core/src/program_joint_integration_tests.rs
  • crates/labcolors-core/src/program_point_causality_tests.rs
  • crates/labcolors-core/src/program_relation_tests.rs
  • crates/labcolors-core/src/program_session.rs

Comment on lines +2335 to +2358
vec![],
evaluator,
)
.with_joint_selection(DeclaredJointSelectionV1::new(vec![state(FIRST)]))
.compile()
.unwrap();
let mut session = compiled.instantiate(STREAM).unwrap();

let error = match session.commit(update(1, 0x00)) {
Ok(_) => panic!("two failures in the fresh recheck must reject the selected state"),
Err(error) => error,
};
assert_eq!(
error,
SessionUpdateError::Plan(ProgramSessionEvaluationError::FinalRecheckViolation {
state_index: 0,
case_index: 0,
constraint: first_violation,
subject: ProgramConstraintSubjectV1::VisibleUnary {
occurrence: OCCURRENCE,
context: appearance_context(),
},
hard_violation_count: 2,
}),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Проверьте исключение report-only violation из итогового счётчика.

report_only пуст, поэтому тест подтверждает только подсчёт двух hard-нарушений. Добавьте report-only constraint, возвращающий Violation, и проверьте, что hard_violation_count остаётся 2. Иначе название теста не покрывает контракт «только hard violations».

🤖 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/program_joint_integration_tests.rs` around lines
2335 - 2358, Расширьте тест вокруг финальной проверки `session.commit(update(1,
0x00))`, добавив constraint с `report_only`, который возвращает `Violation`.
Сохраните ожидаемый `FinalRecheckViolation` и убедитесь, что его
`hard_violation_count` остаётся равным 2, подтверждая подсчёт только
hard-нарушений.

Comment thread crates/labcolors-core/src/program_relation_tests.rs Outdated

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

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

@lemone112
lemone112 merged commit 6c5d6a0 into main Jul 28, 2026
10 checks passed
@lemone112
lemone112 deleted the agent/v5a-core branch July 28, 2026 17:40
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