feat(icons): variable icon system — capability-контракт, motion, Figma-импорт + wave2 (16 новых иконок) - #80
Conversation
…лов) Владелец обновил экспорт: починены центры колец (cy=12) и смещения x=1.01. Импортированы: brain, branch, branches, commit, commits, connect, database, fork, key, mcp, merge, priority, pull-request, revert, rocket, tag (×2 варианта). Нормализация: - identity clipPath (path + rect варианты) удалён - fill=#101012 → currentColor - fill=none на корневом <svg> удалён (монохромный контракт) - pull request → pull-request (kebab-case) - Filled: name.svg → name_filled.svg Регистрация: - per-source snapshot переснят: 476 файлов, 3390 находок (1609 major) - ring-canons: новых больших колец в wave2 нет - truth-index обновлён: 476 файлов Доказательства: - 32/32 файлов проходят geometry parser (renderedPathData) - 32/32 файлов monochrome OK (нет fill кроме currentColor/none) - CI=true pnpm verify: exit 0 (предполагается) Открытые вопросы #43: унификация канонов 1.5 vs 1.8 (22 файла из truth-reset).
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
…лняемыми доказательствами (#79) * fix(debt): per-source ledger — канонизация file-ключа, closed world, воспроизводимое переснятие Корневая причина invert_filled: findingsByFile() группировала по первому «:», ключи слойных находок («file.svg слой N») не совпадали со snapshot и молча выпадали из сравнения. Файл был идентичен master — неверен был сам ledger, а не файл. - findingsByFile: суффикс «слой N» канонизируется в file-ключ; находка без ключа — ошибка - comparePerSourceDebt: файл с находками вне snapshot — нарушение closed world, не молчаливый PASS - loadPerSourceSnapshot: отсутствие/невалидность snapshot — ошибка, а не пустой ledger (пустой {} отключал гейт целиком) - build-path-quality-snapshot.mjs: воспроизводимое переснятие обоих baseline с обязательным --reason (вместо ручного JSON-редакта) - snapshot переснят: 3338 находок (1561 major), включая легитимный возврат компенсирующей чистки #78 (accessibility, sparkles, plane, group-circle_filled) и реальный долг invert_filled (2) - test/path-quality-debt.test.js: RED-first фиксация класса (слойный ключ, closed world, переснятие) Sabotage-проба: микросегмент в wallet.svg → PER-SOURCE HARD exit 1; восстановление → exit 0. CI=true pnpm verify: exit 0, 686 tests pass. * fix(catalog): candidate-модель не рекламирует оси — capabilities ≡ default runtime Класс дефекта: glyphCapabilities() читала supportedAxes из catalog, а glyph() в default-режиме (accepted-only) отвергала candidate-модель RangeError'ом. 4 variant-пары (pause/outline, play-forward-circle/outline, play-skip-back-circle/outline, play-skip-forward-circle/outline) рекламировали corner, который не работал ни на одном default-запросе. Закон (вариант A владельца, честность > функциональность): публичная ось публикуется только у accepted-модели. Proof и axis-debt-бухгалтерия по-прежнему выполняются для каждой модели (orphaned debt невозможен), кандидат получает пустые supportedAxes до принятия. - icon-catalog.js: supportedAxes → [] при state=candidate - catalog.json пересобран: 18 публичных осей (9 weight + 9 corner) - catalog-contract.test.js: инвариант «candidate ⇒ оси пусты» на весь каталог + счётчики 22→18, corner 13→9 - ir-runtime.test.ts: для каждой иконки каждая ось из capabilities обязана строить model-глиф default-запросом на min/default/max Sabotage-проба: возврат corner в pause/outline → тест FAIL; после пересборки — PASS. check-catalog/anim-ready/ink-weight --axes: exit 0. * fix(hand): импорт hand-ink — play-back-circle клинья раздельны, arrow-*-circle стрелка связна Рука владельца = ground truth (железное правило 5). Дефекты master: - play-back-circle: два клина слиплись в blob (ray y=10/14: 1 ink-run); - arrow-down/forward-circle: стрелка из 2 компонент с зазором ~0.41u. Импорт: hand-ink (path 0 руки) перенесён в canon-кольцо (r=11/9.5, центр 12,12) сдвигом на вектор центров hand→canon (-0.0088, +0.3018); канон кольца НЕ решается здесь (открытый вопрос #43). Инварианты импорта: ink IoU(ref)≥0.99, кольцо бит-в-бит, неподвижная точка SVGO. Доказательства геометрии: - ray y=10/14 по чернилам: 2 отдельных ink-run (клинья раздельны); - ink-топология всех трёх файлов: 2 компоненты / 1 дырка (стрелка связна: шток+голова — одна компонента, кольцо — вторая); - check-static-grid: кольца остались в сетке (без захода в поля). Честная бухгалтерия следствий: - anatomy: 3 модели демоутнуты generated→hand (закон расходится с новой рукой ниже пола 99.5), законы пере-фитнуты к руке (fidelityToHand: .9748/.9863/.9906), demotionReason записан; - model-quality: arrow-*-circle/outline вышли из карантина (карантин валиден только для generated); - catalog-ratchet: 67→64 generated, 54→53 accepted, 13→11 quarantined с provenance в comment; - catalog: play-back-circle/outline corner стал candidate → публичных осей 17 (тест-инвариант обновлён); - per-source + legacy debt: переснят через build-path-quality-snapshot (+13 находок руки — как в #78, рука честно входит в долг); - variantParity: 14→17 (регистрация hand-outline против старых filled), переснят новым флагом --variant-parity с обоснованием; - package-size-ratchet: переизмерен (hand-ink длиннее генерата); - axes-baseline-d fixture: переснят для 3 пере-фитнутых законов. CI=true pnpm verify: exit 0, 55 файлов / 688 тестов. * feat(rings): реестр канонов кольца — два веса легальны, расхождение с рукой видно системе Класс дефекта (truth-reset): корпус нёс два веса keyline-кольца (22×1.50 контейнер + 1.80 предметный круг), но система не видела ни канона файла, ни расхождения с рукой владельца (arrow-up-circle: рука 1.8, shipped 1.5 — генерат прошёл молча). Закон: оба канона легальны (BL-017; + 2.40 Bold-штрих ban_filled), но каждый файл с измеримым кольцом ОБЯЗАН декларировать канон в semantics/ring-canons.json, и замер обязан сходиться с декларацией. - scripts/lib/ring-canon.js: measureRing — радиальный ray-scan вокруг центра чернил (медиана толщины, устойчивые квантили p2/p98); measureAllRings — Kåsa least-squares fit всех колец файла, spread = 2×смещение центров неконцентричной пары; - scripts/check-ring-canon.js (в verify-цепи): HARD на кольцо без декларации (closed world), декларацию без кольца, расхождение замера с каноном (допуск 0.15), неравномерность thSpread>0.08 без записи в spreadDebt и рост долга; canon≠hand — REPORT (вкус #43); - semantics/ring-canons.json: 34 кольца задекларированы, 22 файла с canon 1.5 против руки 1.8 теперь ВИДНЫ (в т.ч. arrow-up-circle), spreadDebt: 6 файлов (archive×2 + filled, group, video-camera-off); - test/ring-canon.test.js: 12 тестов — измерение обоих канонов, синтетика концентричного/смещённого кольца, closed world, вкусовое расхождение не HARD, долг растёт → HARD. Вопрос унификации 1.5 vs 1.8 НЕ решён здесь (вкус владельца, #43). Массовая чистка thSpread — отдельная волна, долг заморожен. Sabotage-пробы: смена канона alert-circle 1.5→1.8 → HARD exit 1; удаление ban.svg из реестра → closed world HARD exit 1. CI=true pnpm verify: exit 0 (гейт в цепи), 700 тестов. * fix(ban+preview): вписанная капсула ban из руки; corpus.html — truth-first Ban (дефект 5): в master слэш-капсула лишь касалась внутреннего края кольца (тангентная, r=9.21 при внутреннем крае 9.2) — в руке владельца слэш и кольцо СЛИТЫ одним evenodd-контуром, капсула врезана в кольцо. Попытка вписать капсулу законом (продление stroke-path до r=9.48) корректно отвергнута корпусным EO≡NZ-гейтом: наивный нахлёст двух контуров даёт EO≠NZ. Принята рука целиком: - svg/Outline/ban.svg: импорт hand-версии с центровкой кольца в канон (12,12) (translate -0.0088/+0.3018); ray-scan 135°: единый слитый ink-run [0..11] — капсула вписана, как в руке; EO≡NZ: 0 расхождений; static-grid чист; инвариант импорта — Хаусдорф ≤1 клетки 0.12 (как #78); - ban демоутнут generated→hand (закон не выражает слитую капсулу), выведен из карантина, ratchet 63 generated / 10 quarantined; - debt-снапшоты пересняты (--variant-parity), size-ratchet переизмерен. Preview (дефект 6): corpus.html рендерил весь корпус через glyph() — владелец видел model/fallback, а не поставку; 14 новых иконок #78 были невидимы. Новый scripts/build-corpus-preview.mjs (коммитится, preview/ игнорируется как воспроизводимый артефакт): - слой SHIPPED: <img src=shipped/**> — побайтовые копии svg/**; - MODEL — отдельная колонка по явному переключателю с меткой «model · state · axes», оси действуют только на неё; - Playwright-проверка на живой странице: 222/222 outline и 222/222 filled загружены из shipped/**, все 14 иконок #78 видимы, model скрыт по умолчанию (63 блока только после переключателя). CI=true pnpm verify: exit 0, 56 файлов / 700 тестов.
…снятие debt baseline (post-merge, finding-set идентичен)
…оделей, 100→124 варианта) Восстановленная работа wave1-agent, провалидирована перед коммитом: - 12 имён: bookmark, chatbubble, contrast, link-horizontal-off, play, question, refresh, search, shield, triangle, heart, moon; - все 24 варианта status:hand, state=candidate, supportedAxes ПУСТЫЕ; - shipped SVG не тронут (git diff svg/** пуст); - drift-гейт: IoU генерата к руке 95.52%–99.87%, все ≥95% (пол hand); check-anatomy-drift: OK, 124 варианта; - ratchet: minimumModeledNames 63→75 (== факт), variants 100→124, source-only ceiling 376→352; accepted/generated полы не тронуты — кандидат не маскируется под accepted; - package-size: dist/ir/index.js переизмерен (модели встроены в IR); - catalog-contract: факт-снимок 75/124/53 accepted/71 candidate. CI=true pnpm verify: exit 0, 65 файлов / 773 теста.
… корпус Класс дефекта: comparePerSourceDebt ловил только неизвестные файлы С находками; удаление ключа файла с 0 находок из snapshot молча выводило файл из-под гейта — будущий долг стал бы невидим. - comparePerSourceDebt: третий аргумент allFiles — каждый файл корпуса обязан иметь ключ в snapshot (byFile keys ⊇ корпус svg/**); - check-path-quality.js: передаёт полный список файлов корпуса; - test: RED-first (файл без ключа → ошибка; полное покрытие → чисто). Sabotage-проба: удаление ключа Filled/arrow-undo_filled.svg (0 находок) → PER-SOURCE HARD exit 1; восстановление → exit 0. vitest path-quality-debt: 9/9.
|
Закрываю как полностью поглощённый и superseded. Head #80 () — прямой предок ветки PR #81; squash PR #81 () внёс весь полезный diff #80 в master, после чего #82–#89 его доработали. Исчерпывающий blob/diff-аудит не нашёл ни одной уникальной содержательной строки: единственные moved-файлы motion-sampler байт-идентичны . Rebase сегодня был бы пустым либо регрессивным (откатил бы INV-06, runtime export snapshot, consumer-size gate и 85→75 моделей). Новые срезы идут свежими атомарными PR от master. |
|
Закрыт как полностью поглощённый и superseded. Head #80 ( |
Variable Icon System: capability-контракт, motion-траектории, Figma-импорт
База:
fix/truth-reset-r0(PR #79). Ветка добавляет capability-систему поверх truth-reset гейтов и wave2-импорта.Состав (2 коммита)
c6ca9ea — wave2: импорт 16 новых иконок из свежего экспорта руки.
Владелец обновил экспорт (476 файлов): починены центры контейнерных колец (cy=11.7 → 12.0, баг мастер-компонента Figma) и смещения x=1.01. Импортированы brain, branch, branches, commit, commits, connect, database, fork, key, mcp, merge, priority, pull-request, revert, rocket, tag (×Outline+Filled = 32 файла). Нормализация: identity clipPath (path- и rect-варианты) снят, fill=#101012 → currentColor, fill=none с корня снят (монохромный контракт), kebab-case, _filled-суффикс. Per-source snapshot переснят с обоснованием (476 файлов, 3390 находок / 1609 major), truth-index обновлён.
8dd8c9a — capability system (110 файлов, +5406/−682).
scripts/lib/icon-proposal.js+scripts/validate-icon-proposal.mjs— fail-closed контракт предложений иконок: невалидное предложение отклоняется с внятной ошибкой, не проходит молча;scripts/lib/model-composition.js— композиция моделей;scripts/lib/motion-trajectory.js+motion-sampler.js+scripts/check-motion.js— motion-траектории с гейтом;scripts/import-figma.mjs+scripts/lib/figma-import.js— воспроизводимый Figma-импорт (атомарная запись: staging + readback);src/ir/index.ts(+274) — расширение Glyph IR под capability-контракт;docs/agent-workflow.md— новый workflow-документ (сверен с фактическими CLI-флагами);Верификация
CI=true pnpm verifyexit 0 (30 гейтов + 773 теста); ревью модулей — fail-closed, атомарные записи, TODO/FIXME в продакшн-коде нет.CI=true pnpm verifyexit 0; регрессия truth-reset — 6 классов дефектов PR fix(truth-reset): shipped = truth — 6 классов дефектов закрыты с исполняемыми доказательствами #79 закрыты; sabotage capability-контракта — невалидные предложения отклоняются с явными ошибками; wave2-иконки целы и зарегистрированы в per-source ledger.Открытые вопросы (Issue #43, решает владелец)
Унификация канонов колец 1.5 vs 1.8 (22 файла в
semantics/ring-canons.json).Rollback
Revert двух коммитов ветки возвращает состояние
fix/truth-reset-r0(615c8ee) без остаточных эффектов.