Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/agents/calibration/converter.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Write results to `$RUN_DIR/conversion.json`.
"uncoveredStruggles": [
{
"description": "A difficulty not covered by any flagged rule",
"suggestedCategory": "layout | token | component | naming | ai-readability | handoff-risk",
"suggestedCategory": "structure | token | component | naming | behavior",
"estimatedImpact": "easy | moderate | hard | failed"
}
]
Expand Down
2 changes: 1 addition & 1 deletion .claude/agents/rule-discovery/designer.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ You will receive:
- Read `src/core/rules/rule-config.ts` for score/severity conventions
3. Design the rule:
- **Rule ID**: kebab-case, descriptive (e.g., `missing-component-description`)
- **Category**: existing (`layout | token | component | naming | ai-readability | handoff-risk`) or propose a new category if none fits. New categories require justification.
- **Category**: existing (`structure | token | component | naming | behavior`) or propose a new category if none fits. New categories require justification.
- **Severity**: `blocking | risk | missing-info | suggestion`
- **Initial score**: based on estimated impact on implementation difficulty
- **Check logic**: what condition triggers the violation
Expand Down
4 changes: 2 additions & 2 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ reviews:
Ensure workflows use pnpm/action-setup@v4 and --frozen-lockfile.

pre_merge_checks:
docstring_coverage:
enabled: false
docstrings:
mode: "off"

chat:
auto_reply: true
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/bug.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ body:
attributes:
label: Symptom
description: What's happening? Include error messages, wrong output, or unexpected behavior.
placeholder: "invisible-layer scores -10 (blocking) but hidden layers don't block implementation"
placeholder: "unnecessary-node scores -10 (blocking) but hidden layers don't block implementation"
validations:
required: true
- type: textarea
Expand All @@ -31,7 +31,7 @@ body:
attributes:
label: Affected Files
description: Which source files need changes?
placeholder: "src/core/rules/rule-config.ts, src/core/rules/ai-readability/index.ts"
placeholder: "src/core/rules/rule-config.ts, src/core/rules/structure/index.ts"
validations:
required: false
- type: textarea
Expand Down
6 changes: 3 additions & 3 deletions docs/CALIBRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,11 @@ Real excerpts from calibration debates across 5 fixtures and 7+ rounds.
> Converter (with filtered nodes): "GROUP inside a real UI component causes moderate difficulty, not hard. The hard ratings were from icon nodes."
> Critic: "High confidence, 3 cases. 37.5% change within limit. Severity back to risk."

### ambiguous-structure: validated at -10
### no-auto-layout: validated with absorbed rules

**Consistently confirmed across all fixtures:**
**After absorbing `ambiguous-structure` and `missing-layout-hint`:**
> Converter: "Children named 'Path', 'Path', 'Path' with no semantic distinction — programmatic conversion is impossible without visual rendering."
> Critic: "4 cases, all hard. Score -10 at blocking confirmed. No change needed."
> Critic: "4 cases, all hard. The merged `no-auto-layout` rule now covers these structure clarity signals. Score -7 at blocking confirmed."

### New rule proposals: VECTOR no path data

Expand Down
9 changes: 4 additions & 5 deletions docs/MCP-VS-CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,11 @@ This report documents a side-by-side comparison of analyzing the same Figma desi
| Category | MCP | CLI | Match |
|----------|-----|-----|-------|
| **Overall** | C (67%) | C (67%) | Yes |
| Layout | 100% | 100% | Yes |
| Structure | 100% | 100% | Yes |
| Token | 21% | 21% | Yes |
| Component | 100% | 100% | Yes |
| Naming | 24% | 24% | Yes |
| AI Readability | 59% | 59% | Yes |
| Handoff Risk | 100% | 100% | Yes |
| Behavior | 100% | 100% | Yes |

### Issue Counts

Expand All @@ -37,7 +36,7 @@ This report documents a side-by-side comparison of analyzing the same Figma desi
| **Total Issues** | **5** | **6** | **No** |
| Token issues | 2 | 3 | No |
| Naming issues | 2 | 2 | Yes |
| AI Readability issues | 1 | 1 | Yes |
| Structure issues | 1 | 1 | Yes |

### Issues by Rule

Expand All @@ -46,7 +45,7 @@ This report documents a side-by-side comparison of analyzing the same Figma desi
| `raw-color` | **1** | **2** | **No** |
| `inconsistent-spacing` | 1 | 1 | Yes |
| `default-name` | 2 | 2 | Yes |
| `empty-frame` | 1 | 1 | Yes |
| `unnecessary-node` | 1 | 1 | Yes |

---

Expand Down
42 changes: 18 additions & 24 deletions docs/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,19 @@ Override score, severity, or enable/disable individual rules:

### All Rule IDs

**Layout (9 rules)**
**Structure (9 rules)**

| Rule ID | Default Score | Default Severity |
|---------|--------------|-----------------|
| `no-auto-layout` | -7 | blocking |
| `absolute-position-in-auto-layout` | -10 | blocking |
| `fixed-width-in-responsive-context` | -4 | risk |
| `missing-responsive-behavior` | -4 | risk |
| `group-usage` | -5 | risk |
| `fixed-size-in-auto-layout` | -5 | risk |
| `missing-min-width` | -5 | risk |
| `missing-max-width` | -4 | risk |
| `missing-size-constraint` | -5 | risk |
| `unnecessary-node` | -2 | suggestion |
| `z-index-dependent-layout` | -5 | risk |
| `deep-nesting` | -4 | risk |

**Token (7 rules)**

Expand All @@ -117,13 +118,14 @@ Override score, severity, or enable/disable individual rules:
| `raw-opacity` | -5 | risk |
| `multiple-fill-colors` | -3 | missing-info |

**Component (3 rules)**
**Component (4 rules)**

| Rule ID | Default Score | Default Severity |
|---------|--------------|-----------------|
| `missing-component` | -7 | risk |
| `detached-instance` | -5 | risk |
| `missing-component-description` | -2 | missing-info |
| `variant-structure-mismatch` | -4 | risk |

**Naming (5 rules)**

Expand All @@ -135,23 +137,14 @@ Override score, severity, or enable/disable individual rules:
| `numeric-suffix-name` | -2 | missing-info |
| `too-long-name` | -1 | suggestion |

**AI Readability (5 rules)**
**Behavior (4 rules)**

| Rule ID | Default Score | Default Severity |
|---------|--------------|-----------------|
| `ambiguous-structure` | -10 | blocking |
| `z-index-dependent-layout` | -5 | risk |
| `missing-layout-hint` | -3 | missing-info |
| `invisible-layer` | -1 | suggestion |
| `empty-frame` | -2 | missing-info |

**Handoff Risk (3 rules)**

| Rule ID | Default Score | Default Severity |
|---------|--------------|-----------------|
| `hardcode-risk` | -5 | risk |
| `text-truncation-unhandled` | -5 | risk |
| `prototype-link-in-design` | -2 | suggestion |
| `prototype-link-in-design` | -2 | missing-info |
| `overflow-behavior-unknown` | -3 | missing-info |
| `wrap-behavior-unknown` | -3 | missing-info |

### Example Configs

Expand All @@ -178,12 +171,13 @@ Override score, severity, or enable/disable individual rules:
}
```

**Mobile-first (focus on layout):**
**Mobile-first (focus on structure):**

```json
{
"rules": {
"missing-responsive-behavior": { "score": -10, "severity": "blocking" },
"fixed-width-in-responsive-context": { "score": -8, "severity": "blocking" },
"fixed-size-in-auto-layout": { "score": -8, "severity": "blocking" },
"no-auto-layout": { "score": -12 }
}
}
Expand All @@ -207,7 +201,7 @@ Each custom rule is a JSON object with the following fields:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id` | `string` | Yes | Unique rule identifier (kebab-case recommended) |
| `category` | `string` | Yes | One of: `layout`, `token`, `component`, `naming`, `ai-readability`, `handoff-risk` |
| `category` | `string` | Yes | One of: `structure`, `token`, `component`, `naming`, `behavior` |
| `severity` | `string` | Yes | One of: `blocking`, `risk`, `missing-info`, `suggestion` |
| `score` | `number` | Yes | Penalty score (integer, must be <= 0) |
| `match` | `object` | Yes | Conditions to evaluate (see below) |
Expand Down Expand Up @@ -317,7 +311,7 @@ Frames with many children that should have Auto Layout applied:
```json
{
"id": "large-frame-no-auto-layout",
"category": "layout",
"category": "structure",
"severity": "risk",
"score": -5,
"match": {
Expand All @@ -341,7 +335,7 @@ Hidden nodes buried deep in the tree that add noise:
```json
{
"id": "deep-hidden-layer",
"category": "ai-readability",
"category": "structure",
"severity": "suggestion",
"score": -2,
"match": {
Expand Down Expand Up @@ -418,7 +412,7 @@ I want a custom rule for CanICode that checks: [DESCRIBE WHAT TO CHECK]

Generate a JSON rule object with these fields:
- id: kebab-case identifier
- category: one of layout, token, component, naming, ai-readability, handoff-risk
- category: one of structure, token, component, naming, behavior
- severity: one of blocking, risk, missing-info, suggestion
- score: negative integer (more negative = more severe)
- match: object with conditions (ALL must match). Available conditions:
Expand Down
6 changes: 3 additions & 3 deletions docs/SCORING.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Scoring Model

canicode scores designs on a 0-100% scale across 6 categories:
**layout**, **token**, **component**, **naming**, **ai-readability**, **handoff-risk**.
canicode scores designs on a 0-100% scale across 5 categories:
**structure**, **token**, **component**, **naming**, **behavior**.

## How Scores Are Calculated

Expand Down Expand Up @@ -31,7 +31,7 @@ Issues concentrated in one rule type are easier to fix than scattered issues acr

```
category_score = density * 0.7 + diversity * 0.3
overall_score = average of all 6 category scores (equal weight)
overall_score = average of all 5 category scores (equal weight)
```

The 70:30 ratio prioritizes volume over variety. A design with a single systemic problem (e.g., all frames missing auto-layout) is still very hard to implement even though diversity is low.
Expand Down
8 changes: 4 additions & 4 deletions docs/fixtures/ANALYSIS-VALIDITY-FEEDBACK.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ It is **not** a statistical proof. It assumes: REST fixture JSON + current `rule

### A. Invisible layers + raw color clusters (many Simple DS fixtures)

- **Overrated:** Overall **grade can look decent (A / high B)** while the tree still carries many **invisible-layer** and **raw-color** hits. Severity may keep the headline grade up, but the AI still sees **noise** (extra nodes, ambiguous fills) and may **mis-order or mis-style** visible content. **Pixel outcome** can be worse than the letter grade suggests.
- **Overrated:** Overall **grade can look decent (A / high B)** while the tree still carries many **unnecessary-node** and **raw-color** hits. Severity may keep the headline grade up, but the AI still sees **noise** (extra nodes, ambiguous fills) and may **mis-order or mis-style** visible content. **Pixel outcome** can be worse than the letter grade suggests.
- **Underrated:** Rare for the **same** pattern; occasionally invisible only affects editor hygiene, not export — but REST + rules still complain.
- **Remedies:**
- **Figma:** Delete or detach truly unused layers; replace raw values with variables where the team cares; reduce hidden decoration.
- **Workflow:** Feed **`design-tree`** or a **pruned node list** to the AI so it ignores known-noise IDs.
- **Tooling:** Consider reporting **“visible-only issues”** aggregate for AI-facing summaries; tune `invisible-layer` / `raw-color` weights after calibration for “impact on visual-compare.”
- **Tooling:** Consider reporting **“visible-only issues”** aggregate for AI-facing summaries; tune `unnecessary-node` / `raw-color` weights after calibration for “impact on visual-compare.”

### B. Unscoped large trees (Material 3 & large Simple DS)

Expand All @@ -48,7 +48,7 @@ It is **not** a statistical proof. It assumes: REST fixture JSON + current `rule

### D. Numeric / generic naming (Material 3 community)

- **Overrated:** Score can look **OK on layout** while **ai-readability / naming** tanks — sometimes **underweighted** in how much it confuses **less capable** models (variable names, component names in code).
- **Overrated:** Score can look **OK on layout** while **structure / naming** tanks — sometimes **underweighted** in how much it confuses **less capable** models (variable names, component names in code).
- **Underrated:** For **vision-heavy** codegen (screenshot + structure), **bad names** matter less — score may **undersell** “actually buildable if you ignore names.”
- **Remedies:**
- **Figma:** Rename critical interactive nodes; keep DS naming convention.
Expand Down Expand Up @@ -83,7 +83,7 @@ Names refer to directories under `fixtures/` or `fixtures/done/`. Grades refer t

### `simple-ds-175-9106` / `175-8591` / `175-7790` / `562-9518` — B ~ B+

- **Overrated:** **raw-color + invisible-layer** volume — **B/B+** may **overrate** first-shot pixel match.
- **Overrated:** **raw-color + unnecessary-node** volume — **B/B+** may **overrate** first-shot pixel match.
- **Underrated:** **Detach/instance** and **default-name** sometimes fixable with a strong “use Figma structure as source of truth” prompt.
- **Remedies:** Scope; variable cleanup; explicit **instance** handling in prompt.

Expand Down
Loading