- Date: 2026-05-22
- Status: Accepted
- Feature: URL-import
- Affects: url_import_spec.md § IV Phase 8
Context
После acceptance gate (ADR 0009) проверяет ОДНУ конфигурацию (default state, 1440 viewport, light theme). Это routing decision: "code path сработал или нужен vision?"
Но это не отвечает на другой вопрос: "Мы полностью забрали компонент со всеми его проявлениями?"
Юзер явно отделил концепции:
"ОК, это критерии оценки код справился или подключать вижн. А теперь я хочу обсудить то что нужно забирать из компонента. Критерии того что мы полностью все забрали из ссылки. Вот компонент — мы забрали цвет, токены, состояния — что ещё нужно для того чтобы сказать 'Мы полностью забрали твой компонент, теперь он у нас такой как у тебя на сайте'."
Это отдельная концепция — completeness verification.
| Измерение | Что измеряет | Когда |
|---|---|---|
| Acceptance gate (ADR 0009) | "Code path сработал?" | После каждой generation, для routing |
| Completeness (this ADR) | "Захватили весь компонент во всех проявлениях?" | После финальной TSX, для declaring done |
Evolution
V1 (rejected): weighted multi-dimensional checklist
- color_score × 0.3 + spacing × 0.2 + states × 0.25 + tokens × 0.15 + ...
- Юзер: "не жизнеспособные, документ ради документа"
V2 (rejected): список обязательных полей (color ✓ tokens ✓ states ✓ aria ✓)
- Не отвечает на "полностью" — компонент может иметь все поля но визуально отличаться в edge case
V3 (final): матрица комбинаций
Decision
Completeness = matrix verification across state × viewport × theme:
async function completenessCheck(component, captureMatrix): Promise<CompletenessReport> {
const combinations = generateCombinations({
themes: Object.keys(captureMatrix), // ['light'] or ['light', 'dark']
viewports: [320, 768, 1024, 1440],
states: detectAllStates(component) // ['default', 'hover', 'focus', 'active', 'disabled', ...]
});
const results = await Promise.all(combinations.map(async combo => {
const original = captureMatrix[combo.theme][combo.viewport][combo.state];
const generated = await renderGenerated(component.tsx, combo);
const diff = await pixelmatch(original, generated, {
ignoreText: true, // юзер свой контент вставит
ignoreImages: true
});
return { combo, diff, pass: diff < 0.15 };
}));
return {
complete: results.filter(r => r.pass).length / results.length >= 0.90,
failedCombos: results.filter(r => !r.pass).map(r => r.combo)
};
}Threshold: 90% combinations pass pixel-diff < 0.15.
Why matrix wins
- Эмпирическая, не калибруемая (как и acceptance gate)
- Покрывает проявления компонента, не статические поля — кнопка имеет default/hover/focus/active/disabled × 4 viewports × 2 themes = 40 combinations
- Допускает граничные failures — один редкий state (например custom "loading" в exotic case) не блокирует declaring компонент done
- Failed combinations явно видны в report → юзер знает что именно сломалось ("hover at 320px viewport in dark theme")
ignoreText + ignoreImages— сверяем структуру/spacing/colors, не content (юзер свой текст вставит)
Threshold rationale
pixel-diff < 0.15:
- Строже чем acceptance gate
< 0.30— здесь сверяем тот же компонент в разных combos, не оригинал vs generated - Расхождения должны быть малы (только из-за ignoreText/Images)
90% combinations pass:
- 100% слишком строго — один редкий state может законно ломаться (e.g. browser quirk)
- 80% слишком loose — компонент с 3+ broken states назвать complete нельзя
Consequences
Pros:
- Чёткий definition of "done" — measurable, не subjective
- Граничные fails не топят компонент
- Failed combos surface specific issues для manual review
Cons:
- Compute cost — render 40 combinations per компонент, ~10s overhead
- При low capture matrix (single theme detected, no dark) — fewer combinations, меньше confidence
Capture matrix dependencies
Matrix completeness требует Phase 2 (themes + states + viewports) capture full coverage. Если Phase 2 partial (e.g. failed to detect theme mechanism) → matrix smaller → lower confidence. Это reflected в failed_combinations в manifest.
Alternatives rejected
A. Weighted checklist
- ❌ Same issues как acceptance gate V1 (см ADR 0009)
B. "All required fields filled" check
- ❌ Не отвечает на "полностью" — fields могут быть, edge cases visually ломаются
C. Manual review of every component
- ❌ Не scales — small-biz юзер impотит 10+ компонентов
D. Strict 100% pass
- ❌ False blocks for compliant components с rare edge cases
Cross-references
- Main spec § IV Phase 8
- Main spec § 0.5 Pivot 4 — pivot history
- ADR 0009 — acceptance gate (separate concept)