| name | verify-rule |
| description | Use when verifying a CSS noop rule against real Chromium behavior, checking rule correctness and e2e/unit test consistency. Triggers on "verify rule", "check rule", "re-verify", or reviewing rule accuracy after changes. |
| argument-hint | <rule-id> |
Verify Rule
Verify a CSS noop rule's correctness and test consistency by cross-checking rule source, unit tests, test.html cases, and real Chromium computed styles via Playwright.
Correctness Standard
This project is Chromium-behavior-driven. The ground truth is what getComputedStyle() returns in current Chromium, not the CSS spec alone.
- False positives are worse than false negatives. If behavior is conditional, context-sensitive, or unclear in Chromium, the rule should stay silent.
- A property that is partially effective (e.g. one axis of
place-items still matters) is NOT a no-op — do not warn.
- If you intentionally keep a known false negative, document the trade-off in the rule comment.
Apply this standard at every judgment point in the workflow below.
When to Use
- After modifying a rule's logic or default values
- When auditing whether a rule matches real Chromium behavior
- When test.html cases might have false positives/negatives
- Before merging rule changes
Workflow
digraph verify {
rankdir=TB;
"Read rule source" -> "Read unit tests";
"Read unit tests" -> "Read test.html cases";
"Read test.html cases" -> "Cross-check coverage";
"Cross-check coverage" -> "Has gaps?" [shape=diamond];
"Has gaps?" -> "Report missing coverage" [label="yes"];
"Has gaps?" -> "Run Playwright verification" [label="no"];
"Report missing coverage" -> "Run Playwright verification";
"Run Playwright verification" -> "Visual screenshot check";
"Visual screenshot check" -> "Run unit tests";
"Run unit tests" -> "Report results";
}
Step 1 — Gather Sources
Read these files for the given <rule-id>:
| File | Purpose |
|---|
src/rules/<rule-id>.ts | Rule logic, checked properties, default values |
src/rules/__tests__/<rule-id>.test.ts | Unit test cases and assertions |
examples/test.html (grep for data-rule="<rule-id>") | Browser test cases |
docs/rules/<rule-id>.md | Rule documentation (if exists) |
Step 2 — Cross-Check Coverage
Compare the three layers and report gaps:
- Rule properties vs test.html cases — Does test.html have at least one
expect-warn case per property the rule checks? Does it have expect-ok cases for key bypass conditions (e.g. will-change, parent context)?
- Rule logic vs unit tests — Do unit tests cover all branches? (early returns, edge cases like multi-value properties,
will-change bypass)
- Unit test assumptions vs defaults — Do the
defaultValue constants in the rule match DEFAULT_COMPUTED_STYLES in make-element.ts? Do they match what Chromium actually returns?
- test.html case placement — Are
expect-warn cases under the "Should warn" heading and expect-ok cases under "Should NOT warn"? Misplaced cases are a common source of confusion.
- Label accuracy — Labels are the primary way users understand each test case. They should be self-explanatory without needing to inspect the element:
- warn labels should state what is ineffective (e.g. "div with object-fit: cover", "inline span with aspect-ratio")
- ok labels should explain why the property is effective AND what to expect visually (e.g. "img with object-fit: cover — replaced element, 200x40 SVG cropped to 100x100 square", "video with object-fit — replaced element, empty but object-fit applies")
- Labels for shorthand properties (e.g.
place-items, place-content) should clarify which halves are effective and why
- Labels must not claim behavior that contradicts Chromium reality (e.g. claiming "both halves effective" when one half requires
flex-wrap: wrap)
- When an ok case has limited visual verifiability (e.g. empty video/canvas), the label should acknowledge this so viewers aren't confused
- Visual verifiability — Can you visually confirm the CSS effect (or lack thereof) in the browser? Test cases should include sufficient dimensions (
width, height) and background to make the effect obvious. For example:
- An
inline-grid container without explicit width won't visually show justify-items: center
- A flex container without
flex-wrap: wrap won't visually show align-content: center
Report any gaps found before proceeding to Playwright.
Prerequisites
If running in a git worktree, node_modules may not exist. Run pnpm install first if pnpm test fails with "command not found" errors.
Step 3 — Playwright Verification
Write a temporary Playwright test at e2e/integration/verify-<rule-id>.test.ts:
import { test, expect } from '@playwright/test';
import { fileURLToPath } from 'node:url';
import path from 'node:path';
import { extractElementData } from '../helpers/extract-element-data.ts';
import { analyzeElement } from '../../src/rules/engine.ts';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const TEST_HTML = `file://${path.resolve(__dirname, '../../examples/test.html')}`;
test('verify <RULE_ID> cases in detail', async ({ page }) => {
await page.goto(TEST_HTML);
const cases = page.locator('.case[data-rule="<RULE_ID>"]');
const count = await cases.count();
console.log(`\n=== Found ${count} <RULE_ID> cases ===\n`);
for (let j = 0; j < count; j++) {
const c = cases.nth(j);
await c.scrollIntoViewIfNeeded();
await c.screenshot({
path: `e2e/integration/verify-<RULE_ID>-${j}.png`,
});
}
for (let i = 0; i < count; i++) {
const caseEl = cases.nth(i);
const label = (await caseEl.locator('.label').textContent())?.trim() ?? '(no label)';
const classList = await caseEl.evaluate((el) => Array.from(el.classList));
const expectWarn = classList.includes('expect-warn');
const target = caseEl.locator('[data-target]');
const data = await extractElementData(target);
const warnings = analyzeElement(data);
const matching = warnings.filter((w) => w.ruleId === '<RULE_ID>');
const relevantStyles: Record<string, string> = {};
for (const key of Object.keys(data.computedStyles)) {
relevantStyles[key] = data.computedStyles[key];
}
const status = expectWarn
? matching.length > 0
? 'PASS'
: 'FAIL'
: matching.length === 0
? 'PASS'
: 'FAIL';
console.log(`${status} | ${label}`);
console.log(` Computed: ${JSON.stringify(relevantStyles)}`);
if (matching.length > 0) {
console.log(` Warnings: ${matching.map((w) => w.property).join(', ')}`);
} else {
console.log(` Warnings: (none)`);
}
const others = warnings.filter((w) => w.ruleId !== '<RULE_ID>');
if (others.length > 0) {
console.log(
` Other rules fired: ${others.map((w) => `${w.ruleId}:${w.property}`).join(', ')}`,
);
}
console.log('');
if (expectWarn) {
expect(matching.length, `"${label}" should warn`).toBeGreaterThan(0);
} else {
expect(matching.length, `"${label}" should NOT warn`).toBe(0);
}
}
});
Replace <RULE_ID> with the actual rule ID. Filter relevantStyles to only the properties declared in the rule's requiredProperties for readability.
Run (use PLAYWRIGHT_FORCE_TTY=0 and pipe through cat to capture console.log output in non-TTY environments):
PLAYWRIGHT_FORCE_TTY=0 pnpm test:e2e e2e/integration/verify-<rule-id>.test.ts --reporter=line 2>&1 | cat
Step 4 — Visual Screenshot Check
After the Playwright test runs, review the per-case screenshots (e2e/integration/verify-<RULE_ID>-*.png) using the Read tool to visually confirm:
- warn cases — The CSS property visually has no effect. For example:
aspect-ratio on an inline element: background shows no height is generated (text-height only)
shape-outside on a non-floated element: no visible text wrapping effect
- ok cases — The CSS property visually has an effect. For example:
aspect-ratio on a block element: background area shows height generated by aspect ratio
shape-outside on a floated element: adjacent text wraps around the shape
- Contrast between warn and ok — When viewed side by side, the difference between "property is ignored" and "property is effective" should be obvious. If it's not, the test case needs better styling (background color, dimensions, adjacent content, etc.)
- No unintended side effects — Check that styling added for visual clarity (e.g.
width, background) doesn't trigger warnings from other rules (e.g. width on an inline element triggers inline-no-dimensions)
Report visual issues in the Visual Screenshot Check section of the final report.
Step 5 — Run Unit Tests
pnpm test src/rules/__tests__/<rule-id>.test.ts
Check for failures. If a unit test fails but Playwright passes (or vice versa), the unit test's assumptions may be wrong — investigate the divergence.
Step 6 — Clean Up and Report
- Delete the temporary Playwright test file and screenshots with
rm -f (use -f to avoid interactive confirmation prompts):
rm -f e2e/integration/verify-<rule-id>*.test.ts e2e/integration/verify-<rule-id>-*.png
- Report results in this format:
## Verify: <rule-id>
### Coverage Check
- Rule properties: [list]
- test.html warn cases: [count] / ok cases: [count]
- Unit test cases: [count]
- Gaps: [any missing coverage]
### Playwright Results (Chromium)
| Case | Expected | Result | Key Computed Values |
|------|----------|--------|---------------------|
| ... | warn | PASS | animationDuration: "2s" |
### Unit Test Results
[pass/fail count]
### Label & Visual Check
| Case | Label Accurate? | Visually Verifiable? | Issue |
|------|----------------|---------------------|-------|
| ... | yes | yes | |
### Visual Screenshot Check
Review each per-case screenshot (`verify-<rule-id>-N.png`) and report:
- **warn cases**: Does the screenshot show the property has no visible effect?
- **ok cases**: Does the screenshot show the property is visually effective?
- **warn vs ok contrast**: Is the difference between "ignored" and "effective" obvious at a glance?
- **Side-effect issues**: Does added styling (background, width, etc.) trigger unrelated rule warnings?
| Case | Visually Correct? | Issue |
|------|-------------------|-------|
| ... | yes | |
### Divergences
[Any inconsistencies between unit tests, e2e, and real browser behavior]
Key Checks
- False positive? — Does the rule warn on a declaration that actually has a visible effect in Chromium? This is the most serious defect. Verify by toggling the property in DevTools and observing layout/paint changes.
- Partial effectiveness — A shorthand or composite property where one part matters (e.g.
place-items where one axis is effective) is NOT a full no-op. The rule must not warn.
- Default value mismatch — Rule says
defaultValue: 'ease' but Chromium returns cubic-bezier(...) → silent false negatives. Compare rule defaults against real getComputedStyle() output.
- Shorthand expansion — Rule checks longhand but style is set via shorthand → verify Chromium resolves it to the expected longhand value.
- Other rules firing — A test case triggers warnings from unexpected rules → investigate cross-rule interaction.