Skip to content

feat(core): конфиг-ядро PR-a — ThemeConfig + from_config + ladder/alpha_analog эмиссия (ADR-0001) - #121

Merged
lemone112 merged 17 commits into
mainfrom
feat/config-core
Jul 2, 2026
Merged

feat(core): конфиг-ядро PR-a — ThemeConfig + from_config + ladder/alpha_analog эмиссия (ADR-0001)#121
lemone112 merged 17 commits into
mainfrom
feat/config-core

Conversation

@lemone112

@lemone112 lemone112 commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Зачем

PR-a пути миграции ADR-0001 (эпик ds-config-train, CH-02 t1+t2): движок получает конфиг-вход; вся эмиссия labui-контракта выводима из конфига. Поглощает issue #59 (акцентная эмиссия). WASM/fingerprint — PR-b.

Состав

  • t1: типы ThemeConfig (без serde — JSON в PR-b), валидатор с пределами каждой ручки (вне пределов = ConfigError), NamedRoleTable::from_config, DIP-рефактор resolve_spec_in (Role-путь — обёртка), фикстура labui (20 ролей) + байт-в-байт 240/240 против RoleTable::default() на golden-гриде.
  • t2: рецепт Ladder (rgba-эмиссия: тинт источника × пер-темная альфа позиции; источники Brand|Family|Sentiment(через солвер разведения)|Neutral(pick)); AlphaAnalog на композит-инверсии feat(alpha): композит-инверсия — альфа-аналог солида как чистая физика #119; пересчёт S_PERC_MIN из хром якорей конфига (деривационная идентичность 0.068_703_9 при labui-якорях); закрытое меню 13+2 позиций (Приложение A к ADR); labui_reference до полного consumedRoles.

Заземление и честность

  • Меню позиций и альфы = Figma-рампа @nn (стаб несёт дословно), пер-темные пары — данными.
  • Значенческий гейт: эмиссия представителей всех групп ПОБАЙТНО == строкам стаба в light и dark (+RED-proof мутацией альфы) — класс «имена без значений» закрыт (приёмка поймала дефект заземления neutral≠blue — исправлен со сверкой каждого значения).
  • Info смещается от синего бренда по закону (2.5° < порога разделения) — деривационная идентичность честно скоуплена (Danger/Success/Warning), Info — отдельный тест смещения.
  • Задокументированные gap-и: inverted/edge-нейтральные якоря (не выводятся из тройки anchors — будущее поле конфига), dark-рампы альф акцентов (Figma их пока не несёт).

Верификация

16 сьютов зелёные (275 lib-тестов), golden/240 байт-в-байт/empirical_inventory/s2b-гард целы; clippy -D warnings чист. Изолированные ревью финального состояния: арх-ось PASS_WITH_NOTES (внесено: panic-гард в r3-golden против будущих вариантов, сухие комментарии, долг t3), CoVe-аудит 5/5 SUPPORTED. RED-proof: мутации позиции/семейства/альфы/якоря — все RED.

Коллизия с локом s2b_baseline_guards (1 match-арм в r3) — флагнута владельцу зоны отдельной задачей, байт-дрейфа эмиссии нет.

Summary by CodeRabbit

  • New Features
    • Добавлены публичные конфигурации тем/ролей с валидацией и компиляцией в таблицу ролей.
    • Добавлены полупрозрачные акцентные/сентимент-роля с контрастом по итоговому композиту.
    • Добавлена функция резолва именованных наборов ролей и справочная конфигурация.
  • Bug Fixes
    • Улучшена “честная” обработка граничных случаев (без незаметных клипов) и прозрачных композитов.
  • Documentation
    • Обновлены материалы по правилам лестницы прозрачности и уточнены численные допуски.

Daniel from Labpics and others added 4 commits July 2, 2026 05:16
…р + фикстура labui (t1)

CH-02 t1 конфиг-границы (ADR-0001). Скоуп: типы конфига без serde, валидатор
пределов каждой экспонируемой ручки, DIP-рефактор резолва по &RoleSpec, эталонная
фикстура labui и байт-в-байт тест против сегодняшней эмиссии.

- config.rs: ThemeConfig (Brand/Neutral/Palette/Sentiments/Themes/roles/aliases),
  VcPreset (закрытое меню Srgb|Dim|SrgbIc|DimIc), RoleRecipe (TextAnchor/DjAnchor/
  DecorativeLc/Ladder/AlphaAnalog/Zero). Ladder/AlphaAnalog — честная заглушка с
  верным типом (ConfigError::NotYetImplemented, реализация t2).
- ConfigError: ручной enum + Display + Error (ноль runtime-deps, issue #29).
- Валидатор: пределы каждой ручки с обоснованием в doc-строке; невалидный
  hex/имя/ссылка на несуществующее семейство/роль → ConfigError.
- DIP: resolve_spec_in(&RoleSpec) — общее физ-ядро; resolve_in(Role) стал обёрткой.
  NamedRoleTable + resolve_named_set + ThemeConfig::compile_named_role_table.
- Фикстура labui_reference(): 20 ролей 1:1 из RoleTable::default, нейтраль-тройка
  и tint-ручки из констант semantic.rs (единый источник истины).
- Тесты: байт-в-байт 240 точек (config == default) + RED-proof; валидатор на
  каждую ручку + RED-proof на границах; заглушки t2.

Golden semantic.rs, empirical_inventory-гейт, lint_parity — зелёные.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…PERC_MIN (t2)

Поглощает акцентный GAP #59: лестница акцента/сентимента/бренда как ДАННЫЕ —
один тинт-якорь источника (пер-темно) × закрытая рампа альф Figma @nn.

Ядро:
- crate::ladder — ThemeAnchors (пер-темная четвёрка), LadderTint (Copy-payload,
  разложен по 4 режимам), LadderPosition (закрытое меню 13 позиций + альфы @nn).
- RoleSpec::Ladder{tint, alpha} + RoleSpec::AlphaAnalog{of, alpha} (semantic.rs).
- Resolved::Rgba(RgbaResolved) — rgba(тинт, α) НАПРЯМУЮ (закон лестницы labui,
  композитит браузер) + солид-композит на фоне резолва для замера контраста
  (фаза 1 AA меряет композит). resolve_spec_in — единый сеам физики обоих фронтов.
- BgInput::encoded_display — device-пространство фона для композита.
- sentiment: resolve_smooth_hue_explicit (config-facing), resolve_config_sentiment_solid
  (тинт сентимента = якорь, разведённый с брендом), s_perc_min_from_chromas
  (закон 2·C_rep·sin(20°/2) из конфиг-якорей), s_perc_min_frozen.

Конфиг:
- Brand/PaletteFamily → пер-темные якоря (ThemeAnchors) ДОСЛОВНО из reference §2.
- RoleRecipe::Ladder{source, position} + AlphaAnalog{of, alpha}; LadderSource
  (Brand/Family/Sentiment); валидатор ссылок источника + предел альфы.
- labui_reference расширена акцент/сентимент/FX/альфа-ролями (consumedRoles).

Тесты (RED-proof кусаются):
- diff=пусто против consumedRoles labui (удаляемые по коллапсу перечислены).
- S_PERC_MIN(labui) == 0.068_703_9 (деривационная идентичность, 1e-4) + RED-proof.
- Сентимент-тинт == сырой якорь при hue-дальнем бренде (Danger/Success/Warning);
  Info смещён от синего бренда ПО ПОСТРОЕНИЮ (честная находка, задокументирована).
- rgba-эмиссия + композит; RED-proof мутаций позиции/семейства/альфы.
- Байт-в-байт t1 (240) зелёный; empirical_inventory зелёный.

Приложение A к ADR-0001: меню позиций + провенанс + деривационная идентичность.

Известная коллизия: r3_byte_identity.rs изменён на 1 арм match (вынужденно —
новый вариант Resolved::Rgba); s2b-baseline-guard требует ре-анкора владельцем
эпика s2b (байт-дрейфа НЕТ, r3-тесты зелёные).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…c-строка

Изолированная верификация t2 (arch-reviewer PASS_WITH_NOTES + CoVe SUPPORTED):
- High-1: r3_byte_identity.rs — wildcard `_ => "UNKNOWN"` заменён на
  `other => panic!(...)`, чтобы golden не проглотил молча будущий вариант Resolved.
- Low-2: config.rs — комментарии FX-neutral/skeleton переписаны сухо
  (почему+как, без потока сознания).
- Low-1: wasm/engine.rs — catch-all после Rgba помечен осознанным долгом t3.
- CoVe: LABUI_CONSUMED_ROLES — doc-строка про компромисс зеркала (класс дрейфа
  закрывается гардами поезда labui против живой эмиссии).

Долг (Medium-1, не сейчас): Alpha как value-object вместо голого f64 —
кандидат на будущий рефактор типобезопасности.

Прогоны: cargo fmt/clippy -D warnings чисты; 273 core lib + 12 наборов зелёные;
единственный красный — s2b baseline-guard на r3 (флагнут владельцу, байт-дрейфа нет).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ий тест

Приёмка нашла дефект заземления (посылка «labui Neutral = семейство blue» —
ложна). Сверено построчно со стабом labui packages/colors-stub/contract.css:

(1) НЕЙТРАЛЬНЫЙ источник ≠ blue. Добавлен LadderSource::Neutral(NeutralPick)
    из neutral.anchors (Mid #787880 / Light #FFFFFF / Dark #101012).
    Переведены на него: fx-skeleton-* (тинт #787880, стаб rgb(120 120 128 / …)),
    fx-glow-neutral (белый @52), fx-glow-inverted, fx-focus-ring-neutral,
    fill-neutral. fill-neutral-tinted/border-neutral — алиасы на core
    fill-primary/border-base (стаб var()).
(2) ПЕР-ТЕМНЫЕ альфы: LadderPosition::alpha() → alpha_pair()(light,dark) +
    alpha_for_vc(); RoleSpec::Ladder несёт alpha_light/alpha_dark, резолв
    выбирает по теме. SkeletonBase пер-темна (light @8 / dark @12 по стабу) —
    исправлены перепутанные base/highlight альфы. Добавлены SkeletonBase/
    SkeletonHighlight позиции. Акцентные пары равны (у Figma нет dark-рампов
    альф — стаб держит равными, помечено).
(3) КЛАСС «имена без значений»: значенческий тест
    representative_roles_match_stub_values_light_and_dark — эмиссия rgba(тинт,α)
    представителя каждой группы == строка стаба ПОБАЙТНО в light И dark.
    Исключены намеренно расходящиеся (info — смещение солвером; focus-ring-neutral
    dark / glow-inverted / fill-neutral — задокументированные gap-и). RED-proof
    value_test_bites_on_alpha_mutation (мутация одной альфы → RED, проверено).

Прогоны: fmt/clippy -D warnings чисты; 275 core lib + 20 наборов зелёные;
s2b baseline-guard зелёный (r3/empirical_inventory не тронуты). Приложение A
к ADR-0001 обновлено (пер-темная таблица альф + neutral-источник + значенческая
сверка).

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

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

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: 22 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: 4b4d65cc-b988-42fc-8dc0-27a856b07f02

📥 Commits

Reviewing files that changed from the base of the PR and between efb355c and 54c844c.

📒 Files selected for processing (12)
  • crates/labcolors-core/src/config.rs
  • crates/labcolors-core/src/config/tests.rs
  • crates/labcolors-core/src/ladder.rs
  • crates/labcolors-core/src/semantic.rs
  • crates/labcolors-core/src/sentiment.rs
  • crates/labcolors-core/src/solve.rs
  • crates/labcolors-core/tests/r3_byte_identity.rs
  • crates/labcolors-core/tests/s2b_baseline_guards.rs
  • crates/labcolors-wasm/src/engine.rs
  • crates/labcolors-wasm/tests/wasm_parity.rs
  • docs/decisions/0001-config-boundary.md
  • docs/empirical-inventory.md

Walkthrough

PR добавляет декларативную конфигурацию тем и модель ladder-якорей, расширяет семантику новыми rgba-ролями, обновляет sentiment/solve, реэкспортирует новые API, добавляет downstream-обработку нового варианта Resolved и обновляет документацию и тесты.

Changes

Ladder-роли и конфигурация тем

Layer / File(s) Summary
Примитивы лестницы: якоря, тинты, позиции
crates/labcolors-core/src/ladder.rs
ThemeAnchors, LadderTint и LadderPosition задают выбор якоря и альфы по ViewingConditions и проверяются unit-тестами.
Семантический движок rgba-ролей
crates/labcolors-core/src/semantic.rs, crates/labcolors-core/src/solve.rs
Добавлены RoleSpec::Ladder/AlphaAnalog, Resolved::Rgba, RgbaResolved, NamedRoleTable, resolve_named_set, encoded_display и rgba-форматирование.
Явная политика hue-разрешения и порог S_PERC_MIN
crates/labcolors-core/src/sentiment.rs
resolve_smooth_hue_explicit получает явные preferred_side и hue_floor; добавлены s_perc_min_from_chromas, s_perc_min_frozen и resolve_config_sentiment_solid.
Схема, валидация и компиляция ThemeConfig
crates/labcolors-core/src/config.rs
Добавлены ConfigError, публичные типы схемы, validate(), compile_named_role_table() и labui_reference().
Эмиссия и golden-паритет конфигурации
crates/labcolors-core/tests/...
Проверены byte-identity, RED-proof мутации, Resolved::Rgba-нормализация и representative-role сверки.
Валидация и деривационные контракты конфигурации
crates/labcolors-core/tests/...
Расширены проверки диапазонов, ссылок, компиляции рецептов, S_PERC_MIN, sentiment tint, neutral anchors и preflight-паритета.
Реэкспорт новых модулей и типов из lib.rs
crates/labcolors-core/src/lib.rs
Добавлены модули config/ladder и новые pub use-экспорты.
Обработка Resolved::Rgba в downstream
crates/labcolors-core/tests/r3_byte_identity.rs, crates/labcolors-wasm/src/engine.rs, crates/labcolors-wasm/tests/wasm_parity.rs
Добавлена явная обработка и ловля нового варианта Resolved::Rgba.
ADR-документация и эмпирический инвентарь
docs/decisions/0001-config-boundary.md, docs/empirical-inventory.md
Добавлены приложение о ladder-меню и запись о ACHROMATIC_CHROMA_EPS.

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

Sequence Diagram(s)

sequenceDiagram
  participant ThemeConfig
  participant validate_syntactic
  participant compile_named_role_table
  participant resolve_named_set
  ThemeConfig->>validate_syntactic: validate()
  validate_syntactic-->>ThemeConfig: Ok / ConfigError
  ThemeConfig->>compile_named_role_table: compile_named_role_table()
  compile_named_role_table-->>ThemeConfig: NamedRoleTable
  ThemeConfig->>resolve_named_set: resolve_named_set(bg, table, vc)
  resolve_named_set-->>ThemeConfig: Vec<(String, Resolved)>
Loading

Possibly related PRs

  • Labpics-Team/lab-colors#47: затрагивает тот же semantic.rs, который здесь расширен RoleSpec::Ladder/AlphaAnalog, Resolved::Rgba и NamedRoleTable.
  • Labpics-Team/lab-colors#62: связан с WASM-границей для resolve_set, которую здесь обновляют для нового варианта Resolved::Rgba.
  • Labpics-Team/lab-colors#107: касается sentiment.rs, где здесь добавлены новые конфигурируемые функции порога и резолва сентимент-тинта.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Заголовок отражает основное изменение: ввод ThemeConfig и поддержку ladder/alpha_analog-эмиссии в core.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 feat/config-core

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

…мые ошибки

CI: wasm_parity.rs не знал Resolved::Rgba (тест компилится только под wasm32
— локальный прогон слеп) — явный panic-арм на будущие варианты, не маска.

CodeRabbit (4 major + trivial): (1) дубликаты ключей всех словарей конфига
отвергаются (DuplicateKey; включая алиас, затеняющий роль) — повтор имени
делал lookup неоднозначным; (2) ошибки ссылок различимы: UnknownSentiment/
UnknownRole вместо перегруженного UnknownFamily; (3) неконечные значения
(±∞/NaN) отвергаются и open-сверху пределами (is_finite в check_gt/check_ge);
(4) preferred_side — закрытое меню {-1,+1} (0/2 отвергаются); (5) единый
vc_slot() — обе раскладки четвёрки режимов выбирают слот одним отображением.

Тесты на каждый пункт (4 новых + обновлён alias-тест под различимую ошибку).

@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 `@crates/labcolors-core/src/config.rs`:
- Around line 484-485: `compile_named_role_table()` currently emits only
`self.roles`, so aliases validated by `validate()` and referenced by
`labui_reference()` (including `fill-neutral-tinted` and `border-neutral`) are
missing from `NamedRoleTable`. Update `compile_named_role_table()` in
`config.rs` to include `self.aliases` when building the named-role emission, and
make sure the alias entries resolve to the existing target roles so they are
available in the compiled table.
- Around line 266-267: `compile_named_role_table()` is ignoring
`NeutralConfig::anchors` and always using `semantic::NEUTRAL_HUE_DEG`, so custom
neutral scales never affect the undertone curve. Update the neutral-role
compilation path in `config.rs` to derive the canonical neutral hue from the
provided `NeutralConfig::anchors` instead of the fixed semantic constant, and
thread that value through the same role-table build logic used for the other
named roles. Make sure the new calculation is localized near
`compile_named_role_table()` / `NeutralConfig` and does not leave an unexplained
magic constant.
- Around line 226-232: The UnknownFamily error message in the
ConfigError::UnknownFamily match arm incorrectly says “роль”, which is
misleading for non-role references like sentiments.*. Update the formatting in
config.rs to remove that word and keep the message generic using the
referenced_by and family fields so it applies correctly across all callers.
- Around line 1029-1039: Update the rustdoc on the fixture in config.rs to match
the current t2-expanded shape: the summary still says it covers only 20 emitted
roles and that accents/sentiments/alpha/ladder are t2, but the fixture now also
includes ladder/rgba roles and consumedRoles aliases. Adjust the comments around
the fixture and the resolve_named_set/resolve_set comparison so the description
reflects the actual role set and terminology, using the existing symbols
RoleTable::default, resolve_named_set, and resolve_set to locate the block.
- Around line 672-675: The `if let`-chain in `config.rs` is incompatible with
the declared MSRV 1.85. Update the `cat.preferred_side` check in the relevant
`config` handling logic to avoid `if let ... &&` syntax, either by raising
`rust-version` if that is intended or by rewriting it as a nested `if` using the
existing `cat.preferred_side` conditional path.

In `@crates/labcolors-core/src/config/tests.rs`:
- Around line 910-919: The WCAG assertion in the `composite_wcag` test is too
weak and does not enforce the behavior described in the comment. Tighten the
check in the `r.composite_wcag()` assertion for the transparent `#007AFF` over
white case by comparing against a specific expected low contrast value or a
strict upper bound (instead of the trivial 1..21 range), using the existing
`composite_hex`/`composite_wcag` test flow to keep the intent aligned with the
`r.composite_hex()` and `r.composite_wcag()` methods.

In `@crates/labcolors-core/src/semantic.rs`:
- Around line 1455-1458: The composite values are being computed from
analog.tint, but AlphaAnalog only exposes tint_hex externally, so the measured
composite can differ from what the consumer actually paints. Update finish_rgba
and the AlphaAnalog flow to compute composite_lc/composite_wcag from the emitted
tint_hex (or the quantized tint it represents), and keep composite_over_encoded
aligned with that public output; if exact identity behavior is required, change
the API to expose the unquantized tint instead of relying on tint_hex.
- Around line 1391-1396: The public RoleSpec::Ladder path should validate the
alpha/tint inputs before calling resolve_rgba_direct/composite_over_encoded,
since debug_assert checks in release do not prevent invalid values from
producing bad rgba/metrics. Add a runtime guard in the Ladder handling around
the alpha selection and tint.for_vc(vc) flow to ensure alpha stays in the
expected 0..=1 range and the encoded RGB/tint input is valid before compositing,
and apply the same check in the other affected Ladder branch near the matching
resolve_rgba_direct call.

In `@docs/decisions/0001-config-boundary.md`:
- Around line 201-210: In the decision document, fix the typo in the sentence
about intentionally divergent roles by changing “с ссылкой” to “со ссылкой”;
update the prose in the section containing
representative_roles_match_stub_values_light_and_dark so the wording is
grammatically correct while keeping the rest of the explanation unchanged.
🪄 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: 9dd9a716-f2c2-421c-8d63-cd0f0a361d1a

📥 Commits

Reviewing files that changed from the base of the PR and between 17e9894 and 8cd7e9b.

📒 Files selected for processing (11)
  • crates/labcolors-core/src/config.rs
  • crates/labcolors-core/src/config/tests.rs
  • crates/labcolors-core/src/ladder.rs
  • crates/labcolors-core/src/lib.rs
  • crates/labcolors-core/src/semantic.rs
  • crates/labcolors-core/src/sentiment.rs
  • crates/labcolors-core/src/solve.rs
  • crates/labcolors-core/tests/r3_byte_identity.rs
  • crates/labcolors-wasm/src/engine.rs
  • crates/labcolors-wasm/tests/wasm_parity.rs
  • docs/decisions/0001-config-boundary.md

Comment thread crates/labcolors-core/src/config.rs
Comment thread crates/labcolors-core/src/config.rs
Comment thread crates/labcolors-core/src/config.rs
Comment on lines +672 to +675
if let Some(side) = cat.preferred_side
&& side != 1
&& side != -1
{

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Проверить заявленный Rust toolchain/MSRV без запуска кода репозитория.
fd '^(Cargo\.toml|rust-toolchain(\.toml)?|\.tool-versions)$' -H -t f . \
  -x sh -c 'echo "--- $1"; grep -nE "rust-version|channel|rust" "$1" || true' sh {}

Repository: Labpics-Team/lab-colors

Length of output: 323


🌐 Web query:

Rust if let chains stabilized version 1.85 1.88 reference

💡 Result:

The "let chains" feature, which allows chaining let expressions with && in if and while conditions, was stabilized in Rust 1.88.0 [1][2]. This feature is available exclusively when using the Rust 2024 Edition [3][4]. It is edition-gated because it relies on changes to how if let temporary scopes are handled, which were introduced in the 2024 edition to ensure consistent behavior [3][4]. Key details: - Stabilization Version: Rust 1.88.0 (released June 26, 2025) [1][2]. - Requirement: Must be using the 2024 Edition [3][1]. - Functionality: Allows intermixing let expressions with boolean expressions using && [5][1]. Bindings from a let expression are available to subsequent conditions in the same chain and the consequent block [6][7]. - Precedence/Syntax: Because of ambiguity, let chains cannot be directly combined with || operators; parentheses must be used to group expressions if || is required [6][7].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '660,685p' crates/labcolors-core/src/config.rs | cat -n

Repository: Labpics-Team/lab-colors

Length of output: 1648


if let-chain не совместим с заявленным MSRV 1.85

Cargo.toml указывает rust-version = "1.85", а этот синтаксис требует Rust 1.88 / Edition 2024. Либо поднимите MSRV, либо перепишите на вложенный if.

🤖 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/config.rs` around lines 672 - 675, The `if
let`-chain in `config.rs` is incompatible with the declared MSRV 1.85. Update
the `cat.preferred_side` check in the relevant `config` handling logic to avoid
`if let ... &&` syntax, either by raising `rust-version` if that is intended or
by rewriting it as a nested `if` using the existing `cat.preferred_side`
conditional path.

Comment thread crates/labcolors-core/src/config.rs Outdated
Comment thread crates/labcolors-core/src/config/tests.rs
Comment thread crates/labcolors-core/src/semantic.rs
Comment thread crates/labcolors-core/src/semantic.rs Outdated
Comment on lines +201 to +210
### Значенческая сверка (класс «имя без значения»)

`representative_roles_match_stub_values_light_and_dark` сверяет эмиссию
`rgba(тинт, α)` представителя КАЖДОЙ группы со строкой стаба ПОБАЙТНО в light И
dark (нормализованный формат). Закрывает класс дефекта «роль в diff по имени, но
эмитит не то значение». Исключены намеренно расходящиеся роли (с ссылкой):
`*-info-*` (смещение солвером); `fx-focus-ring-neutral` (dark), `fx-glow-inverted`,
`fill-neutral` — задокументированные gap-и (пер-темный нейтральный край /
inverted-якоря / PROVISIONAL-литерал не выводятся из тройки `neutral.anchors`).

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

Опечатка: «с ссылкой» → «со ссылкой».

✏️ Исправление
-эмитит не то значение». Исключены намеренно расходящиеся роли (с ссылкой):
+эмитит не то значение». Исключены намеренно расходящиеся роли (со ссылкой):
📝 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
### Значенческая сверка (класс «имя без значения»)
`representative_roles_match_stub_values_light_and_dark` сверяет эмиссию
`rgba(тинт, α)` представителя КАЖДОЙ группы со строкой стаба ПОБАЙТНО в light И
dark (нормализованный формат). Закрывает класс дефекта «роль в diff по имени, но
эмитит не то значение». Исключены намеренно расходящиеся роли (с ссылкой):
`*-info-*` (смещение солвером); `fx-focus-ring-neutral` (dark), `fx-glow-inverted`,
`fill-neutral` — задокументированные gap-и (пер-темный нейтральный край /
inverted-якоря / PROVISIONAL-литерал не выводятся из тройки `neutral.anchors`).
### Значенческая сверка (класс «имя без значения»)
`representative_roles_match_stub_values_light_and_dark` сверяет эмиссию
`rgba(тинт, α)` представителя КАЖДОЙ группы со строкой стаба ПОБАЙТНО в light И
dark (нормализованный формат). Закрывает класс дефекта «роль в diff по имени, но
эмитит не то значение». Исключены намеренно расходящиеся роли (со ссылкой):
`*-info-*` (смещение солвером); `fx-focus-ring-neutral` (dark), `fx-glow-inverted`,
`fill-neutral` — задокументированные gap-и (пер-темный нейтральный край /
inverted-якоря / PROVISIONAL-литерал не выводятся из тройки `neutral.anchors`).
🧰 Tools
🪛 LanguageTool

[uncategorized] ~206-~206: Неправильная форма предлога. Исправление: «со ссылкой».
Context: ... Исключены намеренно расходящиеся роли (с ссылкой): *-info-* (смещение солвером); `fx-f...

(S_SO)

🤖 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 `@docs/decisions/0001-config-boundary.md` around lines 201 - 210, In the
decision document, fix the typo in the sentence about intentionally divergent
roles by changing “с ссылкой” to “со ссылкой”; update the prose in the section
containing representative_roles_match_stub_values_light_and_dark so the wording
is grammatically correct while keeping the rest of the explanation unchanged.

Source: Linters/SAST tools

Daniel from Labpics added 5 commits July 2, 2026 08:39
… гарды обхода

4 major: (1) алиасы переносятся в NamedRoleTable (без переноса алиасные роли
контракта — fill-neutral-tinted и др. — терялись при компиляции; эмиссия
потребителем = var()-ссылка, одна истина значения); (2) sentiment_s_perc_min
→ Result — filter_map молча считал порог разделения по неполному набору
категорий (тихая математическая ложь); (3) rgba-путь резолва отвергает
спеку вне домена (RoleSpec публичен — сборка в обход валидатора даёт
Unreachable, не правдоподобный мусор); (4) LadderTint::new валидирует
четвёрку режимов (Err с именем битого режима).

Trivial/minor: Rgba в default-golden — шумная паника вместо маски «не клип»
(дрейф дефолт-таблицы обязан падать); IC-наследование альф закреплено
тестом (пер-темная пара skeleton реально различается); русификация
приложения A. Тесты на каждый гард.
…р, signum

3 major: (1) оттенок нейтрального подтона — из КОНФИГА: явная ручка
hue_override_deg (labui несёт измеренную SSOT 286.0°) либо деривация из
тёмного якоря нейтрали клиента (той же формулой, которой была получена
константа: #101012→285.97°) — labui-константа для чужой нейтрали была
дефектом агностичности; (2) контраст rgba-роли меряется по КВАНТОВАННОМУ
композиту — тому же 8-битному hex, что уходит наружу (закон solve_dj;
неквантованный замер расходился с отданным на LSB); (3) preferred_side
нормализуется до ±1 на публичном входе солвера (множитель направления,
не масштаб). Minor/trivial: rustdoc фикстуры под t1+t2, expect с
обоснованием в ladder-тесте, валидатор hue_override [0,360).
…гичный WCAG-тест

major: наружу уходит 8-битный tint_hex и браузер композитит именно его —
тинт теперь квантуется ДО композита в обоих rgba-путях (quantise_encoded,
hex-roundtrip без строки); composite_hex/Lc/WCAG считаются из эмитируемого
значения (завершение принципа «всё внешнее посчитано из внешнего»).
Равенство композита солиду в alpha-analog держится в LSB-границе (#119).

minor/trivial: expect с обоснованием на hex-парсингах ladder-тестов;
тавтологичная проверка WCAG∈[1,21] заменена содержательной (композит @8
над белым обязан быть почти белым и вдвое контрастнее солидного тинта —
доказывает замер по правильному цвету). «Различать код catch-all» —
отклонено: арм уже помечен осознанным долгом t3, различение кодов там.
…порога, гарды hue

4 major: (1) fx-focus-ring-neutral / fx-glow-inverted — на пер-темных
четвёрках конфига (neutral.edge #101012/#F6F8FA, neutral.inverted
#B0B0B9/#3C3C43 — стаб дословно): дублирование одного края давало
НЕВИДИМОЕ кольцо фокуса на тёмной теме; без поля pick — честная ошибка
MissingNeutralAnchors, не выдумка; обе роли теперь в точном value-тесте
обеих тем; (2) замороженный labui-S_PERC_MIN больше НЕ подмешивается в
config-путь (s_min_deg на константе завышал порог низкохромным палитрам
чужим законом — мог опустошить legal arc); (3) preferred_side
нормализуется до ±1 (р-3 фикс МОЛЧА не применился: node-replace без
assert + CRLF/LF-смесь в репо — CAPA: все replace с assert и
EOL-автодетектом); (4) ахроматичные источники оттенка: серая нейтраль
без hue_override — AchromaticHueSource; серый бренд — разведение
сентиментов честно отключено (сентимент = сырой якорь; порог 1e-7
технический — числовая определённость atan2, не перцептивная политика).

minor/trivial: expect на hex тестов лестницы; labui_reference —
задокументирован как КАНОНИЧЕСКИЙ конфиг (переезд в пакет = PR-b);
граничный тест α=1.0 vs 1.0+ε; тесты MissingNeutralAnchors/achromatic.
…ению

Три из четырёх major — один класс (ложноположительный Ok preflight-а:
ахроматичная нейтраль, отсутствующие edge/inverted, битый hex в заданных
краях). Закрыт не заплатками, а по построению: validate() = компиляция с
отброшенным результатом — второго списка проверок не существует, паритет
validate/compile не может разъехаться; структурная фаза выделена в приватный
validate_syntactic (компиляция зовёт её — не validate: рекурсия). Тест-паритет
на корпусе деривационных ошибок сверяет обе ошибки байт-в-байт.

Невозможный порог хорды (s_perc_min > 2C): клип-в-180° больше не скармливается
p-норм солверу — smooth_separation ≥ s_min перелетает диаметраль, легальное
множество вырождается в точку меры нуль и скан-сетка legalize_hue давала бы
ложный «пустая дуга». Сатурация решается аналитически: диаметральный оттенок =
максимум разведения («максимально приближенный приемлемый», директива
владельца), пол-блокировка → граница пола; мусор-входы инверсии хорды — Err.
Случай реален: приглушённый тёмный якорь при хромных светлых соседях.

Домен alpha-analog: симметричный с прямым rgba-путём гард в
resolve_rgba_inverted — недоменная α публичной RoleSpec резолвится в честный
Unreachable, а не в правдоподобный hex через кламп резолвера инверсии
(недоменный солид по построению невозможен: LadderTint::new валидирует квад).

Сопутствующее: ахроматичный якорь СЕМЕЙСТВА → сырой якорь (тот же закон, что
серый бренд: нет носителя оттенка — нет разведения); ACHROMATIC_CHROMA_EPS
переехал к закону в sentiment.rs — реестр строка 38, GROUNDED с вычисленными
границами (мин. 8-бит хрома 1.06e-3, f64-шум ≲1e-12); старый ассерт
hue_floor=359.999 → Ok был ровно флагнутым ложноположительным preflight-ом —
обновлён на честную семантику (в диапазоне, но дуга пуста).

@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

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/sentiment.rs (1)

653-660: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Добавьте доменный guard для brand_hue и hue_floor.

Сейчас resolve_config_sentiment_solid проверяет anchor и s_perc_min, но brand_hue = NaN или hue_floor = Some(NaN) может пройти дальше и дать не Err, а правдоподобный hex/отключённый floor.

Предлагаемый guard
 pub fn resolve_config_sentiment_solid(
     family_anchor_hex: &str,
     brand_hue: f64,
     hardness: f64,
@@
     preferred_side: f64,
     s_perc_min: f64,
 ) -> Result<String, String> {
+    if !brand_hue.is_finite() {
+        return Err(format!("brand_hue вне домена: {brand_hue}"));
+    }
+    if let Some(floor) = hue_floor {
+        if !floor.is_finite() || !(0.0..360.0).contains(&floor) {
+            return Err(format!("hue_floor вне домена: {floor}"));
+        }
+    }
     let _ = chroma_fraction; // хрома тинта = хрома якоря (сохраняем солид якоря);

Согласно path instructions, crates/labcolors-core/**/*.rs: «Float-точность» и «Error handling».

🤖 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/sentiment.rs` around lines 653 - 660,
resolve_config_sentiment_solid currently validates the anchor and s_perc_min,
but it still allows non-finite domain inputs to slip through. Add an explicit
guard near the start of resolve_config_sentiment_solid for brand_hue and
hue_floor so NaN/invalid values are rejected with Err before any color
resolution logic runs, and make sure the same validation covers both the raw
brand_hue argument and the inner value of hue_floor when present.

Source: Path instructions

🤖 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/config/tests.rs`:
- Around line 1433-1497: The “complete preflight” test is tautological because
validate() already delegates to compile_named_role_table().map(drop), so it only
verifies compile_named_role_table() behavior for the three derivation cases.
Update the test name/comment in validate_is_a_complete_preflight to describe it
as a regression guard for specific compile errors, and keep the assertions
focused on the concrete error variants (AchromaticHueSource,
MissingNeutralAnchors, InvalidHex) via validate() and compile_named_role_table()
so the intent matches the implementation.

---

Outside diff comments:
In `@crates/labcolors-core/src/sentiment.rs`:
- Around line 653-660: resolve_config_sentiment_solid currently validates the
anchor and s_perc_min, but it still allows non-finite domain inputs to slip
through. Add an explicit guard near the start of resolve_config_sentiment_solid
for brand_hue and hue_floor so NaN/invalid values are rejected with Err before
any color resolution logic runs, and make sure the same validation covers both
the raw brand_hue argument and the inner value of hue_floor when present.
🪄 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: ed27b05a-a430-4e57-a925-0a3198b267ec

📥 Commits

Reviewing files that changed from the base of the PR and between 8cd7e9b and efb355c.

📒 Files selected for processing (7)
  • crates/labcolors-core/src/config.rs
  • crates/labcolors-core/src/config/tests.rs
  • crates/labcolors-core/src/ladder.rs
  • crates/labcolors-core/src/semantic.rs
  • crates/labcolors-core/src/sentiment.rs
  • docs/decisions/0001-config-boundary.md
  • docs/empirical-inventory.md

Comment thread crates/labcolors-core/src/config/tests.rs
Daniel from Labpics added 7 commits July 2, 2026 10:09
…ия, паблик-гарды углов

2 major: (1) при поле, блокирующем диаметраль, берётся граница легальной дуги
[floor, 360°) с БОЛЬШИМ разведением от бренда (не всегда floor — прежний
«детерминизм к полу» противоречил декларированному максимуму разведения);
верхняя открытая граница — достижимая точка 360°−1e-9 (суб-LSB отступ);
зеркальный тест-корпус на оба исхода; (2) домены α разводить НЕ стали —
отклонено с основанием: контракт РОЛИ = (0,1] (α=0 — невидимая роль; тот же
предел, что у конфиг-валидатора), α=0 принимает только библиотечный
resolve_alpha_analog (вырожденный ответ tint=фон — его домен, не ролевой);
починен реальный дефект — рассинхрон доков RoleSpec::AlphaAnalog ([0,1] → (0,1]
с объяснением границы слоёв).

minor: паблик-гарды resolve_config_sentiment_solid — неконечный brand_hue и
недоменный hue_floor (вне [0,360)) в сатурированной ветке уходили мимо солвера
прямо в oklab_lc_to_hex тихим неверным hex → честный Err + мусор-тесты;
ACHROMATIC_CHROMA_EPS: GROUNDED → SSOT-TRACKED (внешнего стандарта не
существует, деривация закрыта и живёт в таблице реестра — GROUNDED обещает
цитируемый стандарт); PartialEq/NaN у ConfigError — отклонено с основанием
(IEEE-семантика f64-полей, как у самого f64; дроп PartialEq сломал бы
assert_eq всех потребителей) + doc-нота на enum.

trivial: предикат коллапс-ролей ВЫВОДИТСЯ из деклараций COLLAPSED_ROLES
(glob-сопоставитель + значенческий RED-proof гард) — второй вручную
синхронизируемый список гнил молча; значенческая сверка со стабом: rgb
побайтово + α числом с допуском 1e-12 — Display-сравнение f64 хрупко к
хвостам представления.
…ле t2

Разовая правка залоченного r3_byte_identity.rs (арм Resolved::Rgba) была
конверсией enum в #[non_exhaustive]: с ней r3 закрыт к будущим расширениям
Resolved (wildcard-паника — новый вариант не требует правки файла, но не
проходит golden молча). Лок гарда = «чисто против HEAD», не вечная заморозка:
осознанная правка становится новым анкором через коммит + PR-гейт. Байт-дрейфа
эмиссии нет: r3 240-cell golden + споты зелёные, nested-прогон
baseline_r3_byte_identity_tests_pass — ok.
…наррации

Ссылки на раунды ревью, задачи эпика (t1/t2/t3, №г/№д), «решение владельца» и
даты процессов — разговор с ревьюером, а не ограничение кода: читателю пакета
они не дают ничего и выглядят чужеродно. Каждый такой комментарий переписан до
сухого «почему» (само основание везде сохранено); провенанс данных (даты
замеров Figma/стаба) оставлен — он отвечает «с какого снимка истины взято
значение». Ссылка на локальный путь эпика вне репо заменена самими источниками
(Figma-файл + reference/ + стаб labui). Сообщение об ошибке NotYetImplemented
больше не отсылает к внутренней задаче.
…ии, ADR

Сообщение RoleOutcome::Unreachable у rgba-ролей несло внутренний код задачи —
а это наблюдаемая поверхность API, не комментарий; заменено описанием причины
(solid-only surface). Атрибуции решений (owner-провизион, owner-approved) и
коды задач в заголовках ADR убраны — основание остаётся, происхождение
решения читателю кода не нужно. Ссылка ADR на grounding-файл вне репо
заменена самим источником (переменные Figma + путь обхода).
…ходов

Ошибка сентимент-солвера (пустая легальная дуга, недоменные углы) наружу —
собственным вариантом ConfigError::SentimentResolution, а не маской InvalidHex:
потребитель матчится по вариантам, и ошибка политики/геометрии под видом
ошибки парсинга hex ломала бы различение. Валидация hardness/s_perc_min
перенесена ДО ахроматичного fast path — недоменная ручка не может «повезти»
в зависимости от цвета якоря. Публичный resolve_smooth_hue_explicit получил
домен-гард (конечные углы, s_min в [0,180], пол в [0,360)) — NaN в
signed_delta/smooth_separation давал бы NaN-оттенок вниз по физике, а скан
legalize_hue на NaN не завершается осмысленно.

Отклонено с основанием: #[non_exhaustive] на RoleSpec — атрибут уже стоит
(semantic.rs); придирка к GROUNDED-маркеру ACHROMATIC_CHROMA_EPS —
маркер уже SSOT-TRACKED. Доки пары альф позиции уточнены: пару несёт каждая
позиция, расходятся значения только у скелетон-базы.
…ючей

Канонический домен [0, 360) получил один дом (sentiment, рядом с законом) и
один хелпер проверки check_hue_floor_domain для обоих публичных входов — два
независимых литерала/блока одного домена в цветовом коде были классом тихого
расхождения; config импортирует границы (направление зависимостей внутрь).
Дока провенанса альф называет солидные позиции их реальными ключами контракта
(label-primary, не primary — авторы конфигов парсят key()). Тест пары альф
фиксирует наследование базовой темы IC-режимами — будущая ic-ветка в
alpha_for_vc не проедет молча.
Гейт-1 честно поймал немаркированные HUE_DOMAIN_*: каждая константа
перцептивных модулей обязана нести paper-trail. Обе — определение домена
(угол по модулю 360°), не политика: SSOT-TRACKED + строки 39/40 реестра.
@lemone112
lemone112 merged commit 1b428d5 into main Jul 2, 2026
5 checks passed
@lemone112
lemone112 deleted the feat/config-core branch July 2, 2026 09:36
lemone112 added a commit that referenced this pull request Jul 3, 2026
…амок README (#136)

* docs(readme): синхронизация с фактическим кодом ядра

Секция ролей устарела полностью: реально 20 ролей (Role::ALL), имена
label-* (HIG-переименование из text-*), Border/Shadow разветвлены,
добавлено семейство Fill, роль Surface удалена, дефолтный подтон —
RoleChroma::Curve (тонированный), а не ChromaPolicy::Neutral (другой
enum решателя). Таблица переписана построчно по RoleTable::default().

- пример API семантики: Role::TextPrimary → Role::LabelPrimary, реальные
  значения (#0A0A10, lc 102.7) посчитаны кодом; пример компилируется
- API-пример и пример семантики закреплены doctest-замком в lib.rs
  (#[cfg(doctest)] include_str! README) — rust-блоки компилируются навсегда;
  иллюстративные блоки/формулы помечены text
- «Структура проекта» дополнена реальными модулями (accent, alpha,
  chromafast, cleanliness, config, greyfast, ladder, lut, wcag, oklch,
  gamma_data) с назначениями из шапок
- «Тесты»: полный набор CI-гейтов (clippy+fmt, test, audit, wasm+headless,
  npm typecheck/test) вместо заниженного
- «Что дальше»: убран сделанный runtime-engine, surface-jnd переформулирован
  под реальность (роли surface нет, border-*/fill-* уже якорные)

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

* docs(pkg): формат эмиссии — vars несут oklch, не hex

После релиза 0.4.0 (#129/#130) CSS-переменные несут готовое
oklch(L% C H [/ A]) (wasm/lib.rs oklch_css), а сырой #RRGGBB остаётся
данными роли (roles.<ключ>.hex). Исправлены вводный абзац, пример vars
(реальные oklch-строки) и описание vars/SolvedColor; добавлено поле css
(готовое oklch(L% C H)) — сверено с TS-типами wasm/lib.rs.

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

* docs(adr): ADR-0001 принят и внедрён

Статус «предложено» → «принято, внедрено» (config.rs — #121, wasm
loadConfig — #122). Синхронизированы имена API: RoleTable::from_config →
ThemeConfig::compile_named_role_table → NamedRoleTable, резолв —
resolve_named_set. Клейм про отпечаток актуализирован: отпечаток
загруженного конфига реально вычисляется (FNV-1a над DTO, config_dto.rs)
и продевается в кэш-ключ через loadConfig; встроенная дефолт-таблица
остаётся на DEFAULT_TABLE_FINGERPRINT = 0, корректность при смене конфига
держит wholesale clear(). Историческая аргументация не тронута.

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

* docs(core): актуализация комментариев по фактическому коду

Только комментарии и doc-строки, поведение не тронуто.

- semantic.rs: проза шапки модуля и doc-строк констант называла роли
  text-* как текущие — обновлено на label-* (упоминания «Was text-*»
  как история оставлены)
- cache.rs: шапка и doc DEFAULT_TABLE_FINGERPRINT утверждали «отпечаток —
  константа-заглушка, пока жива только дефолт-таблица» — устарело:
  loadConfig влит, отпечаток конфига вычисляется в engine.rs и продевается
  в ключ, корректность держит wholesale clear()
- dto.rs: набор ролей уже 20 — комментарий больше не подаёт «10 → 20» как
  будущее; issue #59 (акцентная лестница) — отдельное будущее изменение
- benches/resolve_set.rs: хроматика больше не «падает в полный live-solver
  ~1 ms» — chromafast влит (memo), в steady state бенч меряет O(1)-путь
  ~0.8–1.2 µs; стейл «12 ролей» убран

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

* docs(pkg): TranslucentRole в union + справочник loadConfig/recheckContrast/muddiness/confidence

H1: union RoleResult потерял TranslucentRole — реально 4 состояния
(lib.rs:100). Добавлено описание TranslucentRole (поля из TS-секции
lib.rs:82-98) и «одно из четырёх состояний».

L2: справочник API дополнен методами движка, сверенными с TS-секцией
lib.rs — loadConfig(json)→16-hex отпечаток (главная фича конфиг-границы),
recheckContrast(bgHex,fgHexes,theme)→Float64Array (примитив adaptTheme,
adapt-theme.d.ts:7), muddiness(hex)→number, confidence(hex)→number.

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

* docs(readme): фиксы по фактическим значениям и структуре гейтов

- M1: комментарий sample_hex(13) — реальный вывод, пересчитан кодом
  (["#FFFFFF", "#F8F8FA", "#E7E8EC", ..., "#101012"])
- M2: mermaid dark #101012 — J' ≈ 9.1 (light.at(1.0).jp = 9.05), было ≈ 4
- L1: «пять гейтов» → четыре CI-джоба (lint/test/audit/wasm); npm typecheck/
  test — блокирующий шаг внутри wasm-джоба (ci.yml)
- M6: «акцентная лестница как рецепт (#59)» — рецепт ladder влит и поглотил
  GAP #59 (config.rs:26); открытое = PR-c (ломающая чистка ядра) + поезд labui
- заметки: снята временная формулировка «сегодня они держат»; карта помечена
  как продакшн-модули (тест-модули golden_tests.rs/config/tests.rs вне карты)

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

* docs(adr): сняты внутренние противоречия под статусом «внедрено»

M3: клеймы, устаревшие после мержа #121/#122:
- S_PERC_MIN уже пересчитывается из конфиг-якорей (тест
  s_perc_min_recomputed_from_config_anchors_matches_frozen), не «БУДЕТ»
- ladder влит (RoleSpec::Ladder, crate::ladder) и поглотил GAP #59 — больше
  не «единственный рецепт без прототипа»
- IC_DECORATIVE_FLOOR_MIN конфигом НЕ экспонирован (сверено с TS ThemeConfig)
  — убран из списка экспонируемых ручек, помечен как физика ядра
- «Путь миграции»: PR-a/PR-b помечены [сделано, #121/#122], поезд/PR-c
  [открыто]; имена API в выполненных шагах синхронизированы

M4: эмиссия oklch, не rgba — движок эмитит oklch(L% C H / α); несуществующий
Resolved::Rgba → Resolved::Translucent (semantic.rs:1122).

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

* docs(wasm): свип rgba→oklch на границе эмиссии + четыре исхода

Только комментарии/doc-строки, поведение не тронуто. WASM — граница CSS-
эмиссии, где заявляется эмитируемая форма:

- M4: dto.rs, engine.rs, lib.rs — «emission is rgba(tint, alpha)» / «наружу
  уходит rgba» / «rgba-роли лестницы» → oklch(L% C H / A); поле tint_hex
  «CSS rgba() carries» → «oklch(… / A) carries»
- M5: dto.rs шапка — «#59 accent ladder (a new resolved shape)» противоречил
  RoleOutcome::Translucent, уже присутствующему ниже; переформулировано: набор
  уже 20, лестница #59 добавила Translucent, дальнейшие исходы проходят так же
- dto.rs: «three honest outcomes» → four (RoleOutcome несёт 4 варианта:
  Color/None/Translucent/Unreachable)

Ядро (semantic.rs/config.rs) не тронуто: там «rgba» — внутреннее имя пути
резолва (согласовано с функциями resolve_rgba_*), а не CSS-клейм.

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

* docs(adr): нормативные секции сверены с кодом (раунд-3, потребительский FAIL)

Автор конфига больше не вводится в заблуждение — каждый клейм по коду:

- Приложение A: таблица позиций 15 → 25 (LadderPosition::ALL, ladder.rs:214-240);
  добавлены NeutralFill×4, NeutralBorder×2, Shadow×4 с точными пер-темными α
  (alpha_pair, ladder.rs:277-291)
- «SkeletonBase — единственная пер-темная альфа» неверно: пер-темные несут
  скелетон + нейтральная рампа + тени (11 позиций); переписано
- brand.anchor «один hex» → пер-темная четвёрка ThemeAnchors {light,dark,
  light_ic,dark_ic} (config.rs:295; согласовано с :190)
- VC-пресеты snake «srgb_ic|dim_ic» → kebab «srgb-ic|dim-ic» (config_dto.rs:92;
  snake давал бы invalid_config)
- меню рецептов 5 → 6: добавлен decorative-lc (config.rs:446); kinds — kebab
- neutral(pick) 3 → 5: добавлены Edge, Inverted (config.rs:508)
- fx-focus-ring-neutral/fx-glow-inverted заземлены пиками Edge/Inverted
  (config/tests.rs:1237-1242)
- тени: «переход на альфа-якоря вне поезда» устарело — уже полупрозрачные
  ladder-позиции (config/tests.rs:1286-1295)
- двойной enum тем «унифицируется» → унифицирован (theme.rs:15)
- golden semantic.rs:3352-3655 → тест resolve_set_golden_hex_is_byte_for_byte_stable,
  const GOLDEN ≈3785
- Значенческая сверка: «rgba(тинт, α)» — внутренний формат core-теста против
  rgb-стаба, НЕ CSS-эмиссия (та oklch); уточнено

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

* docs: дешёвые фиксы читаемости README и пакета (раунд-3)

README:
- UCS-формулы: реализация lcs.rs → формулы в spaces/cam16.rs (ucs_j/ucs_m),
  lcs.rs их применяет
- сквозная нумерация: сняты орфанные «2.»/«3.» с ### Кривая/### Контраст
  (перед ними шёл ### ViewingConditions без номера)
- глоссы для дизайнера при первом употреблении: JND (минимально заметная
  глазу разница), C1-непрерывность (гладкая, без изломов производной)

packages/colors:
- убрана колонка brotli из таблицы размеров (CI меряет только raw+gzip,
  ci.yml:245-252), добавлена честная строка провенанса
- добавлена опция root в WatchThemeOptions (watch-theme.d.ts:23, Node)

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

* docs(adr): точный указатель ThemeAnchors — определён в ladder.rs

Финдинг закрывающего верификатора раунда-3 (recommended minor): тип
определён в ladder.rs:56, config.rs лишь использует его полем Brand.anchors.

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

---------

Co-authored-by: Claude Code <daniilerosov12@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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