🛡️ Enforcement Rules — Mandatory Gate
6 enforce rules bắt buộc cho MỌI tác vụ tạo/sửa/review/kiểm tra showcase, component, hoặc demo.
Khi nào chạy? TRƯỚC khi code (§1 Pre-work Gate) và SAU khi code (§2 Post-work Audit). Ai trigger?
new-showcase.md,component-lifecycle,ds-architect.md— hoặc agent tự trigger khi nhận task liên quan.
§0 — TASK RECEPTION (bắt buộc khi nhận task)
Khi agent nhận BẤT KỲ task nào liên quan showcase/component/demo/docs/style/theme:
- Tạo mới
- Sửa / edit / fix
- Review / kiểm tra / audit
- Bất kỳ tác vụ tạo HTML/CSS/JS output
- Sửa docs template (
preview-extras.css,components.css, preview HTML trongcomponent-previews.js) - Tạo / sửa style (
styles/*.json) hoặc theme (themes/*.json) - Review / audit docs output
Agent PHẢI tuân thủ flow sau — KHÔNG ĐƯỢC bỏ qua:
NHẬN TASK (sửa / tạo mới / review / kiểm tra showcase/component/demo)
│
├─ §1 PRE-WORK GATE (bắt buộc TRƯỚC khi code)
│ ├─ Đọc enforce-rules.md
│ ├─ Đọc knowledge-rules.json (query section liên quan)
│ ├─ Đọc ux-research SKILL.md (§5, §6, §7)
│ ├─ Check variables.css CỦA SHOWCASE (không phải DS core)
│ └─ Output: "PRE-WORK GATE ✅ PASSED"
│
├─ THỰC HIỆN CODE
│ └─ Mỗi quyết định phải cite rule ID (VD: "theo R3, min 44px")
│
└─ §2 POST-WORK AUDIT (bắt buộc SAU khi code)
├─ ENF-1: Check BS-1→5, R3, T10/T11, F1/F3
├─ ENF-2: Scan icon text
├─ ENF-3: Check inline components
├─ ENF-4: Check preview entry exists (component work)
├─ ENF-5: Audit CSS class hardcodes (pseudo-elements, easing, sizing)
└─ Output: Audit report table
│
├─ ✅ ALL PASS → proceed to /post-change
└─ ❌ FAIL → STOP → report violations → user review
⚠️ KHÔNG TUÂN THỦ = FAIL = STOP Agent KHÔNG ĐƯỢC tiếp tục code nếu chưa qua Pre-work Gate. Agent KHÔNG ĐƯỢC báo hoàn thành nếu chưa qua Post-work Audit. Nếu audit FAIL → STOP ngay → output report → chờ user review.
§1 — PRE-WORK GATE (chạy TRƯỚC khi code)
// turbo-all
BẮT BUỘC hoàn thành TRƯỚC KHI viết bất kỳ CSS/HTML/JS nào.
Step 1: Đọc UX Rules
☐ Đọc ux-research SKILL.md — focus:
• §5 Component Behavior (states, keyboard, button sizes BS-1→BS-5)
• §6 Typography (T1 font ≥14px, T10/T11 title sizes)
• §7 Accessibility (F1 focus ring, F3 focus trap, ARIA patterns)
• §2 Interaction (6 states, touch targets)
Step 2: Scan DS Component Inventory
## List tất cả components hiện có trong DS core
dir /b "design-system\components md\*.md" | findstr /v "ATOMIC-MAPPING COMPONENT-ROADMAP"
→ Output = DS Component Whitelist — danh sách components đã có. → Ghi nhận whitelist này để dùng ở §2 Post-work Audit (ENF-3).
Step 3: Đọc ATOMIC-MAPPING.md
☐ Đọc design-system/components md/ATOMIC-MAPPING.md
→ Biết token mapping cho từng component
→ Biết UI Layer + Density Tier assignment
Output — Pre-work Gate Confirmation:
🛡️ PRE-WORK GATE: ✅ PASSED
☑ UX Rules đã đọc (§5, §6, §7, §2)
☑ DS Components: {N} components available
☑ ATOMIC-MAPPING.md đã đọc
→ Proceeding to implementation...
§2 — POST-WORK AUDIT (chạy SAU khi code, TRƯỚC /post-change)
Chạy 5 enforcement checks trên output vừa tạo/sửa.
ENF-1: UX Compliance Check
Audit output đáp ứng UX rules đã đọc ở pre-work:
☐ Font-size ≥ 14px cho body/interactive text? (T1)
☐ Heading hierarchy đúng? (T4: h1 → h2 → h3, không skip)
☐ Focus ring dùng var(--ring)? (F1)
☐ ARIA roles/attributes đầy đủ? (F3, B7)
☐ Touch targets ≥ 44×44px? (R3)
☐ Button sizes theo BS-1→BS-5? (§5)
☐ Action group placement đúng? (AG-1→AG-3)
☐ prefers-reduced-motion nếu có animation? (M1)
→ PASS: Tất cả ☑ → tiếp tục → FAIL: Ghi nhận violations → AUTO-FIX → re-audit
ENF-2: Icon Text Character Ban
TUYỆT ĐỐI KHÔNG dùng text characters làm icon. Tất cả icons PHẢI là SVG.
Blacklist — FORBIDDEN characters:
✕ × ▼ ▾ → ← ↑ ↓ ‹ › « » − • ● ○ ■ □ ★ ☆ ✓ ✗ ☰ ⋮ ⋯ ▶ ◀ △ ▽ ◆ ◇
Scan scope: Chỉ check bên trong interactive/icon contexts:
<button>,<a>,.icon,.btn, icon containers- CSS
content: "..."pseudo-elements dùng cho icon - KHÔNG flag: Content text (paragraphs, headings, descriptions)
Thay thế đúng:
<!-- ❌ SAI — icon text -->
<button class="btn-close">✕</button>
<span class="icon">▼</span>
<a class="nav-link">← Back</a>
<!-- ✅ ĐÚNG — SVG icon -->
<button class="btn-close" aria-label="Close">
<svg><use href="#ic-close"/></svg>
</button>
<span class="icon"><svg><use href="#ic-chevron-down"/></svg></span>
<a class="nav-link">
<svg><use href="#ic-arrow-left"/></svg> Back
</a>
→ PASS: 0 icon text characters found
→ FAIL: List violations → AUTO-FIX (replace with SVG <use>) → re-audit
ENF-3: Inline Component Prohibition
KHÔNG tự viết component inline nếu component đó:
- ĐÃ CÓ trong DS core → dùng trực tiếp
- CHƯA CÓ trong DS core → STOP → báo user → lên kế hoạch tạo mới
Scan scope — áp dụng cho TẤT CẢ contexts:
| Context | Files cần scan |
|---|---|
| Showcase | showcase/{name}/*.css, showcase/{name}/*.html |
| Docs template | preview-extras.css, components.css, component-previews.js (preview HTML) |
| Style/theme | styles/*.json, themes/*.json — check component token refs cho comp chưa tồn tại |
Detection — scan output cho patterns:
☐ Có class .dropdown / .modal / .tabs / .select / .dialog / .toast /
.accordion / .drawer / .popover / .tooltip mà KHÔNG reference DS core?
☐ Có viết CSS cho component behavior (hover states, focus trap, transitions)
mà DS core đã có sẵn?
☐ Có duplicate CSS rules cho component đã tồn tại trong ATOMIC-MAPPING.md?
☐ [DOCS] Preview HTML trong component-previews.js có tự tạo component
thay vì dùng DS class/token?
☐ [STYLE/THEME] Token JSON có ref tới component chưa tồn tại trong
ATOMIC-MAPPING.md? (VD: tạo --comp-xyz-* cho comp chưa có spec)
Decision flow:
Component cần dùng?
│
├─ Có trong DS whitelist (Step 2)?
│ → ✅ Dùng trực tiếp, KHÔNG viết CSS mới
│
└─ KHÔNG có trong DS whitelist?
→ ❌ STOP — KHÔNG viết inline workaround
→ Báo user: "Component {X} chưa có trong DS core.
Đề xuất tạo mới theo component-lifecycle workflow."
→ Chờ user approve → tạo via component-lifecycle
[DOCS context] Preview HTML tự tạo component markup?
→ ❌ STOP — preview PHẢI dùng DS class patterns
→ Nếu DS chưa có → báo user, KHÔNG viết workaround inline
[STYLE/THEME context] Token ref tới comp chưa tồn tại?
→ ❌ STOP — tạo comp spec TRƯỚC (component-lifecycle),
rồi mới tạo tokens
→ PASS: Tất cả components dùng từ DS core hoặc đã báo user → FAIL: List inline components → STOP → báo user (KHÔNG auto-fix)
ENF-4: Preview Entry Gate
Mỗi component PHẢI có preview entry trong component-previews.js.
📌 Root cause: Checkbox issue — component CSS có
top: 1px; left: 5pxhardcode nhưng không bị phát hiện vì thiếu preview audit pipeline.
Check:
☐ Component có entry trong component-previews.js?
☐ Preview HTML dùng DS tokens (KHÔNG hardcode px/colors)?
☐ build-docs.js output hiển thị "N/52 components have live previews"?
☐ Preview bao gồm đủ states: default, hover, disabled?
☐ Icon dùng icon() helper (Lucide SVG, KHÔNG text emoji)?
Preview HTML token rules:
| Property | ❌ Hardcode | ✅ Token |
|---|---|---|
| Spacing/gap | gap: var(--spacing-3) |
gap: var(--spacing-3) |
| Sizing | width: 40px |
width: calc(var(--spacing) * 10) |
| Font | font-size: var(--font-size-sm) |
font-size: var(--font-size-sm) |
| Color | color: #666 |
color: var(--muted-foreground) |
| Easing | ease |
var(--easing-standard) |
| Radius | border-radius: var(--comp-radius) |
border-radius: var(--comp-radius) |
→ PASS: Entry exists + 0 hardcodes
→ FAIL: Missing entry → add to component-previews.js → rebuild docs
ENF-5: CSS Class Hardcode Audit
Audit CSS class definitions trong preview-extras.css và components.css cho hardcodes.
📌 Root cause:
.checkbox:checked::after { top: 1px; left: 5px }— hardcoded positioning sẽ break khi density scale thay đổi.
Files to audit:
design-system/scripts/docs/template/preview-extras.cssdesign-system/scripts/docs/template/components.css
Check mỗi CSS class cho:
☐ Pseudo-element positioning: có `position: absolute` + `top/left: Npx`?
→ Fix: dùng `display: grid; place-content: center`
☐ Hardcoded easing: có `ease`, `ease-in-out`, `ease-out` raw?
→ Fix: dùng `var(--easing-standard)`
☐ Hardcoded duration: có `150ms`, `200ms`, `300ms` raw?
→ Fix: dùng `var(--duration-fast-1)`, `var(--duration-normal-2)`, etc.
☐ Hardcoded sizing: có `40px`, `48px`, `20px` raw (KHÔNG trong spacing scale)?
→ Fix: dùng `calc(var(--spacing) * N)` hoặc `var(--spacing-N)`
☐ Missing bg/fg pair: có `background: var(--primary)` mà thiếu `color:`?
→ Fix: thêm `color: var(--primary-foreground)`
Quick scan command:
## Tìm hardcoded px (trừ border-width, shadow, 0px)
Select-String '\d+px' design-system/scripts/docs/template/preview-extras.css | Where-Object { $_ -notmatch 'spacing|radius|border-width|shadow|0px|var\(' }
## Tìm raw easing
Select-String 'ease[^-]|ease;|ease-in-out|ease-out' design-system/scripts/docs/template/preview-extras.css
→ PASS: 0 hardcodes found → FAIL: List violations → AUTO-FIX → re-audit
ENF-6: Slot Compliance
Mọi component/showcase/demo output PHẢI tuân thủ Figma Slot system.
📌 Source of truth:
knowledge/slot-manifest.json— slot registry (R1-R4 grammar)knowledge/slot-convention.md— CSS naming rules (structural vs BEM)design-system/code-connect/code-connect.config.json— Code Connect configdesign-system/code-connect/slot-api.d.ts— typed slot interfacesdesign-system/code-connect/preferred-instances.json— preferred Figma instances
Check — Component work (tạo/sửa component .md hoặc preview):
☐ Component có `## Slot Map (Figma ↔ Code)` section trong spec .md?
→ Nếu KHÔNG → thêm theo format chuẩn (xem app-bar.md làm mẫu)
☐ Slot names trong spec match slot-manifest.json?
→ Đối chiếu: Figma Slot name + data-slot value + CSS Class
☐ Component có entry trong code-connect.config.json?
→ Nếu KHÔNG → thêm entry mới với slots + template
☐ HTML skeleton/preview dùng data-slot attributes?
→ Mỗi slot element PHẢI có data-slot="{component}-{slot-name}"
Check — Showcase/demo work (tạo/sửa HTML output):
☐ HTML output có data-slot attributes cho structural slots?
→ Structural: data-slot cho header, body, footer (nếu component hỗ trợ)
☐ Slot nesting đúng hierarchy (root → structural → inner)?
→ VD: data-slot="card" > data-slot="card-header" > data-slot="card-title"
☐ Không tự tạo slot name mới ngoài slot-manifest.json?
→ Slot name PHẢI tồn tại trong manifest hoặc được đăng ký trước
Check — Style/theme work:
☐ Component slot CSS class references (.slot-header, .slot-body, .slot-footer)
đều tồn tại trong components.css Slot System section?
Decision flow:
Component output có slots?
│
├─ Có trong slot-manifest.json?
│ → ✅ Dùng data-slot values từ manifest
│
└─ KHÔNG có trong manifest?
→ ❌ STOP — KHÔNG tự tạo slot name
→ Cập nhật slot-manifest.json TRƯỚC
→ Sau đó thêm Slot Map vào spec .md
→ Sau đó thêm entry vào code-connect.config.json
→ PASS: Tất cả slots mapped + data-slot present + Code Connect entry exists → FAIL: List missing slots → fix theo flow trên → re-audit
§3 — AUDIT REPORT FORMAT
Sau khi chạy 5 checks, output report theo format:
### 🛡️ Enforcement Audit Report
**Scope**: {file/folder đã audit}
**Date**: {YYYY-MM-DD}
| Rule | Status | Details |
|------|--------|---------|
| ENF-1 UX Compliance | ✅ PASS / ❌ FAIL | {N violations found} |
| ENF-2 Icon Text Ban | ✅ PASS / ❌ FAIL | {N text icons found} |
| ENF-3 Inline Component | ✅ PASS / ❌ FAIL | {N inline components} |
| ENF-4 Preview Gate | ✅ PASS / ❌ FAIL | {N components missing previews} |
| ENF-5 CSS Hardcode | ✅ PASS / ❌ FAIL | {N hardcoded values in CSS} |
| ENF-6 Slot Compliance | ✅ PASS / ❌ FAIL | {N missing slot maps / data-slot / CC entries} |
#### ENF-4 Violations (nếu có)
| # | Component | File | Issue |
|---|-----------|------|-------|
| 1 | checkbox | component-previews.js | Missing preview entry |
#### ENF-5 Violations (nếu có)
| # | File | Line | Found | Fix |
|---|------|------|-------|-----|
| 1 | preview-extras.css | 874 | `top: 1px; left: 5px` | `display: grid; place-content: center` |
| 2 | preview-extras.css | 860 | `ease` | `var(--easing-standard)` |
VERDICT: ✅ ALL PASS → proceed to /post-change
❌ FAIL → {action required}
Auto-fix Rules
| Rule | Auto-fixable? | Action |
|---|---|---|
| ENF-1 | ✅ Partial | Fix font-size, add ARIA, add focus ring → re-audit |
| ENF-2 | ✅ Yes | Replace text char with SVG <use> → re-audit |
| ENF-3 | ❌ No | STOP → báo user → chờ approve → tạo component mới |
| ENF-4 | ✅ Yes | Add preview entry → rebuild docs → re-audit |
| ENF-5 | ✅ Yes | Replace hardcode with token → re-audit |
| ENF-6 | ✅ Yes | Add Slot Map + data-slot + CC entry → re-audit |
ENF-3 là BLOCKING — không thể auto-fix vì component mới phải đi qua lifecycle đầy đủ (design analysis → token mapping → validation).
Anti-patterns
| ❌ KHÔNG LÀM | ✅ LÀM ĐÚNG |
|---|---|
| Bỏ qua pre-work gate, code luôn | Đọc UX rules + scan DS inventory TRƯỚC |
Dùng ✕ × ▼ → làm icon |
Dùng SVG <use href="#ic-name"/> |
Tự viết .custom-select inline |
Dùng DS select component hoặc báo user |
| Audit xong FAIL nhưng vẫn commit | Fix ALL violations trước khi /post-change |
| Chỉ fix 1 file, bỏ qua blast radius | Scan toàn bộ output cho cùng pattern |
| Tạo component mà không add preview | Add entry vào component-previews.js + rebuild |
position: absolute + top/left: Npx cho centering |
display: grid; place-content: center |
Raw ease / ease-in-out trong transition |
var(--easing-standard) |
Tạo component HTML không có data-slot |
Thêm data-slot cho mọi slot element |
| Tự nghĩ slot name mới | Dùng slot name từ slot-manifest.json |
width: 40px; height: 48px hardcode sizing |
calc(var(--spacing) * N) |
| Chỉ check preview HTML, bỏ qua CSS class | Audit cả preview-extras.css + components.css |
| Fix 1 file CSS, quên file kia | Blast radius: cả preview-extras.css LẪN components.css |