Skip to content

fix: internal calibration CLI improvements (#63)#82

Merged
let-sunny merged 10 commits intomainfrom
fix/calibration-cli-issues-63
Mar 25, 2026
Merged

fix: internal calibration CLI improvements (#63)#82
let-sunny merged 10 commits intomainfrom
fix/calibration-cli-issues-63

Conversation

@let-sunny
Copy link
Copy Markdown
Owner

@let-sunny let-sunny commented Mar 25, 2026

Summary

  • calibrate-run: Remove unused outputPath from call to runCalibrationAnalyze()
  • orchestrator: Accept CalibrationConfigInput (input type) so callers can omit fields with schema defaults
  • calibrate-evaluate optional args and calibrate-gap-report min-repeat edge case already fixed on base branch

Depends on #81

Closes #63

Test plan

  • pnpm lint passes
  • pnpm test:run 590/590 passes

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor

    • Reorganized design validation rules into updated categories: "structure" and "behavior" now replace previous category grouping, reducing total categories from 6 to 5.
    • Consolidated and updated rule definitions for consistency checking.
  • New Features

    • Added validation for component variant consistency, overflow detection, and wrap behavior handling.

let-sunny and others added 9 commits March 26, 2026 04:19
Reclassify categories: layout + ai-readability → structure, handoff-risk → behavior.
Merge overlapping rules: no-auto-layout absorbs ambiguous-structure + missing-layout-hint,
fixed-size-in-auto-layout absorbs fixed-width-in-responsive-context,
missing-min-width + missing-max-width → missing-size-constraint,
invisible-layer + empty-frame → unnecessary-node,
hardcode-risk removed (covered by absolute-position-in-auto-layout).
Add 3 new rules: overflow-behavior-unknown, wrap-behavior-unknown, variant-structure-mismatch.
Final count: structure(9) token(7) component(4) naming(5) behavior(4) = 29 rules.

Closes #79

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…-size)

Merged rules should provide more detailed fix guidance that covers
all absorbed symptoms, not just the base rule's original fix.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Was too vague ("Use a consistent naming convention"). Now includes
specific examples and explains why AI needs consistent naming.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…checks, test fixes

- Add INSTANCE to isContainerNode helper (structure rules)
- Guard noUncheckedIndexedAccess: early continue for undefined children
- Skip wrap-behavior-unknown when children lack bounding box data
- Add +1 tolerance comment for floating-point rounding in overflow check
- Fix misleading test title for hidden overlapping children case
- Add 48x48 boundary test for unnecessary-node placeholder exemption

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…c assertions

- Add boundary-condition tests for text-truncation-unhandled (length=50, width=300, length=51)
- Fix non-deterministic test in responsive-fields: remove if-guard, assert deterministically
- Rename misleading test title to match actual expectation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
TypeScript strict types + JSDoc on public APIs serve as documentation.
The 80% threshold wasn't respecting the configured 40% override anyway.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… accuracy

- Rename test titles to match actual scenarios (both missing vs one missing)
- Add minWidth to fixture that tests maxWidth-only path
- Add "only minWidth missing" test for complete coverage of 3 violation paths

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove `outputPath: "unused"` from calibrate-run's call to
  runCalibrationAnalyze, since the function never uses it
- Add CalibrationConfigInput type (z.input) so the function accepts
  optional fields with defaults (outputPath, maxConversionNodes, etc.)
- calibrate-evaluate optional args and calibrate-gap-report minRepeat
  edge case were already fixed on this branch

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 25, 2026

📝 Walkthrough

Walkthrough

A comprehensive restructuring of the rule categorization system, replacing layout, ai-readability, and handoff-risk categories with structure and behavior, reorganizing rule modules accordingly, introducing new structure and behavior rules, removing obsolete rules, and updating related engine logic, configurations, and tests.

Changes

Cohort / File(s) Summary
Category & Contract Updates
src/core/contracts/category.ts, src/core/contracts/calibration.ts
Updated CategorySchema enum from ["layout","token","component","naming","ai-readability","handoff-risk"] to ["structure","token","component","naming","behavior"]. Updated CATEGORY_LABELS and CATEGORY_DESCRIPTIONS accordingly. Added CalibrationConfigInput type alias for Zod input shape.
Rule Contract Restructuring
src/core/contracts/rule.ts
Updated RuleId union by removing layout/ai-readability/handoff-risk rules (e.g., fixed-width-in-responsive-context, ambiguous-structure, invisible-layer, empty-frame, hardcode-risk) and adding structure/behavior rules (e.g., fixed-size-in-auto-layout, missing-size-constraint, z-index-dependent-layout, unnecessary-node, variant-structure-mismatch, overflow-behavior-unknown, wrap-behavior-unknown). Changed DEPTH_WEIGHT_CATEGORIES from ["layout", "handoff-risk"] to ["structure", "behavior"].
Removed Rule Modules
src/core/rules/layout/index.ts, src/core/rules/ai-readability/index.ts, src/core/rules/handoff-risk/index.ts
Deleted three entire rule module directories: layout (9 rules including noAutoLayout, absolutePositionInAutoLayout, fixedSizeInAutoLayout), ai-readability (5 rules including ambiguousStructure, zIndexDependentLayout, invisibleLayer), and handoff-risk (rules including hardcodeRisk; behavior rules like textTruncationUnhandled and prototypeLinkInDesign were moved).
Added Structure Rule Module
src/core/rules/structure/index.ts
New module with 9 exported structure rules: noAutoLayout, absolutePositionInAutoLayout, fixedSizeInAutoLayout, missingSizeConstraint, missingResponsiveBehavior, groupUsage, deepNesting, zIndexDependentLayout, and unnecessaryNode (merges invisible-layer and empty-frame logic).
Updated Behavior Rule Module
src/core/rules/behavior/index.ts
Removed hardcodeRisk. Reclassified textTruncationUnhandled and prototypeLinkInDesign from "handoff-risk" to "behavior" category. Added two new behavior rules: overflowBehaviorUnknown and wrapBehaviorUnknown.
Updated Rule Registry
src/core/rules/index.ts, src/core/rules/rule-config.ts
Updated barrel exports to use ./structure/index.js and ./behavior/index.js instead of ./layout/index.js, ./ai-readability/index.js, and ./handoff-risk/index.js. Reorganized RULE_CONFIGS with updated structure/behavior rules and adjusted preset filtering logic in getConfigsWithPreset (dev-friendly and ai-ready presets).
Engine Scoring Updates
src/core/engine/scoring.ts, src/core/engine/scoring.test.ts
Updated TOTAL_RULES_PER_CATEGORY by replacing layout (8→9) with structure and adjusting component (3→4); removed ai-readability and handoff-risk, added behavior. Updated CATEGORY_WEIGHT and getCategoryLabel mappings. Test assertions updated to expect 5 categories instead of 6 with new category keys and per-category scoring expectations.
Integration & Engine Tests
src/core/engine/integration.test.ts, src/core/engine/rule-engine.test.ts
Updated integration test category breakdown from 6 to 5 categories with new keys ["behavior","component","naming","structure","token"]. Updated rule-engine test comment to reference structure instead of layout.
Structure Rule Tests
src/core/rules/structure/no-auto-layout.test.ts, src/core/rules/structure/responsive-fields.test.ts, src/core/rules/structure/z-index-dependent-layout.test.ts, src/core/rules/structure/unnecessary-node.test.ts
Added comprehensive test suites for new/moved structure rules. Updated category expectations and unified missing-min-width/missing-max-width tests into missing-size-constraint.
Behavior Rule Tests
src/core/rules/behavior/overflow-behavior-unknown.test.ts, src/core/rules/behavior/wrap-behavior-unknown.test.ts, src/core/rules/behavior/prototype-link-in-design.test.ts, src/core/rules/behavior/text-truncation-unhandled.test.ts
Added test coverage for new behavior rules (overflowBehaviorUnknown, wrapBehaviorUnknown) and updated existing tests to reflect behavior category instead of handoff-risk.
Component Rule Updates
src/core/rules/component/index.ts, src/core/rules/component/variant-structure-mismatch.test.ts
Added new variantStructureMismatch component rule that detects structural differences among component variants.
Deleted Legacy Rule Tests
src/core/rules/layout/\\*.test.ts, src/core/rules/ai-readability/\\*.test.ts, src/core/rules/handoff-risk/\\*.test.ts
Removed 13 test files for obsolete/relocated rules: no-auto-layout.test.ts, absolute-position.test.ts, fixed-width-in-responsive-context.test.ts, missing-responsive-behavior.test.ts, group-usage.test.ts, deep-nesting.test.ts, ambiguous-structure.test.ts, z-index-dependent-layout.test.ts, missing-layout-hint.test.ts, invisible-layer.test.ts, empty-frame.test.ts, hardcode-risk.test.ts, and prototype-link-in-design.test.ts (from handoff-risk).
Custom Rule & Analysis Tests
src/core/rules/custom/custom-rule-loader.test.ts, src/agents/evidence-collector.test.ts, src/agents/gap-rule-report.test.ts, src/agents/report-generator.test.ts, src/agents/analysis-agent.test.ts
Updated test fixtures and assertions to use "structure" instead of "layout" and reflect new category universe including "behavior" instead of "ai-readability"/"handoff-risk".
Orchestrator & Calibration
src/agents/orchestrator.ts, src/agents/orchestrator.test.ts
Updated runCalibrationAnalyze to accept CalibrationConfigInput instead of CalibrationConfig. Updated test data to use new category structure in scoreReport.byCategory.
CLI & Configuration
src/cli/commands/internal/calibrate-run.ts, src/core/ui-constants.ts, src/core/report-html/index.ts
Removed unused outputPath: "unused" option from runCalibrationAnalyze call. Updated CATEGORY_DESCRIPTIONS constant. Changed Category Gauges grid from sm:grid-cols-6 to sm:grid-cols-5 in HTML report.
Minor Updates
src/core/rules/naming/index.ts, .coderabbit.yaml
Enhanced inconsistent-naming-convention rule fix message with concrete examples. Disabled docstring coverage pre-merge check in CodeRabbit config.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • PR #81: Performs the identical category restructuring (layout/ai-readability/handoff-risk → structure/behavior) with the same rule module reorganization, contract updates, and test modifications across the same codebase areas.
  • PR #59: Introduces the CLI module structure that the main PR's calibrate-run.ts change builds upon; the main PR removes an unused option from a command refactored in that PR.
  • PR #71: Adds unit tests to scoring.ts and rule-engine.ts which are directly modified by this PR's category and rule contract changes, creating a direct dependency relationship.

Poem

🐰 Rules were scattered, left and right—
Layout here, readability's flight,
Now they're dancing, neat and tight,
Structure! Behavior! What a sight!
Reorganized with all my might! 🎯

🚥 Pre-merge checks | ✅ 1 | ❌ 4

❌ Failed checks (4 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title focuses on calibration CLI improvements, but the changeset contains extensive rule category reclassification (layout→structure, removal of ai-readability/handoff-risk) affecting many core modules beyond just CLI. Clarify the title to reflect the scope: e.g., 'refactor: restructure rule categories and calibration CLI improvements' to better represent the full changeset.
Linked Issues check ⚠️ Warning The PR partially addresses linked issue #63: calibrate-run's outputPath is removed (✓), and CalibrationConfigInput is added (✓). However, items 1, 3, 4, and 5 from #63 (calibrate-evaluate optional args, calibrate-gap-report minRepeat edge case, list-rules global mutation, calibrate-prune-evidence exit codes) are not present in this changeset. Address all five coding items from #63, or clarify that this PR is partial and open a separate issue for items 1, 3, 4, 5.
Out of Scope Changes check ⚠️ Warning The PR includes extensive out-of-scope changes unrelated to #63: rule category reclassification (layout→structure, ai-readability/handoff-risk→behavior) affecting 40+ files, rule deletions/additions, and test updates across the codebase beyond calibration CLI fixes. Separate the rule reclassification changes into a distinct PR; keep this PR focused on the calibration CLI improvements from #63.
Docstring Coverage ⚠️ Warning Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/calibration-cli-issues-63

Comment @coderabbitai help to get the list of available commands and usage tips.

@let-sunny let-sunny marked this pull request as ready for review March 25, 2026 20:12
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/core/rules/structure/z-index-dependent-layout.test.ts (1)

4-83: 🧹 Nitpick | 🔵 Trivial

Consider restoring boundary condition tests.

Based on the AI summary, this test file previously included tests for:

  1. Exact 20% overlap boundary — The implementation uses overlapArea > smallerArea * 0.2 (strictly greater than), so exact 20% overlap should return null. This boundary test would catch off-by-one changes to the threshold.
  2. Children without absoluteBoundingBox — The implementation handles this with if (!boxA || !boxB) continue;, but a regression test ensures this graceful handling persists.

These boundary conditions are important for preventing regressions. Consider restoring them:

💚 Suggested boundary tests
it("returns null when overlap is exactly 20% (boundary)", () => {
  // Create children where overlap area = exactly 20% of smaller element
  const childA = makeNode({
    id: "c:1",
    absoluteBoundingBox: { x: 0, y: 0, width: 100, height: 100 }, // area = 10000
  });
  const childB = makeNode({
    id: "c:2",
    // 20% of 10000 = 2000, so overlap needs to be exactly 2000
    // overlap of 50x40 = 2000
    absoluteBoundingBox: { x: 50, y: 60, width: 100, height: 100 },
  });
  const node = makeNode({
    type: "FRAME",
    children: [childA, childB],
  });
  expect(zIndexDependentLayout.check(node, makeContext())).toBeNull();
});

it("returns null when children have no absoluteBoundingBox", () => {
  const childA = makeNode({ id: "c:1" });
  const childB = makeNode({ id: "c:2" });
  const node = makeNode({
    type: "FRAME",
    children: [childA, childB],
  });
  expect(zIndexDependentLayout.check(node, makeContext())).toBeNull();
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/rules/structure/z-index-dependent-layout.test.ts` around lines 4 -
83, Add two regression tests to cover boundary conditions: one that constructs
two children via makeNode whose overlap area is exactly 20% of the smaller
element and asserts zIndexDependentLayout.check(node, makeContext()) returns
null (verifying the implementation's strict > 20% threshold), and another that
creates two children without absoluteBoundingBox properties and asserts
zIndexDependentLayout.check(...) returns null (verifying the early-continue
handling when boxA/boxB are missing); place these alongside the existing tests
referencing zIndexDependentLayout.check, makeNode, and makeContext so future
changes won't regress these cases.
src/agents/orchestrator.ts (1)

174-185: ⚠️ Potential issue | 🟠 Major

Honor targetNodeId when the caller provides it.

The schema accepts targetNodeId, but Lines 182-185 still build analyzeOptions only from the node ID extracted out of input. A caller that passes targetNodeId separately will silently analyze the wrong subtree.

🔧 Suggested fix
   const parsed = CalibrationConfigSchema.parse(config);
   const { file, fileKey, nodeId } = await loadFile(parsed.input, parsed.token);
+  if (parsed.targetNodeId && nodeId && parsed.targetNodeId !== nodeId) {
+    throw new Error("targetNodeId conflicts with the node id encoded in input");
+  }
 
-  const analyzeOptions = nodeId ? { targetNodeId: nodeId } : {};
+  const targetNodeId = parsed.targetNodeId ?? nodeId;
+  const analyzeOptions = targetNodeId ? { targetNodeId } : {};
   const analysisResult = analyzeFile(file, analyzeOptions);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agents/orchestrator.ts` around lines 174 - 185, runCalibrationAnalyze
builds analyzeOptions from the nodeId returned by loadFile but ignores a
caller-supplied parsed.targetNodeId; update the logic in runCalibrationAnalyze
to honor parsed.targetNodeId (e.g. use parsed.targetNodeId if present, otherwise
fall back to nodeId from loadFile) when constructing analyzeOptions before
calling analyzeFile so the correct subtree is analyzed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/core/engine/scoring.ts`:
- Around line 75-80: TOTAL_RULES_PER_CATEGORY is hard-coded and can get out of
sync with the actual registered rules; replace the manual map by computing
per-category counts at module initialization from the authoritative rule
registry (e.g., iterate the registered rules/definitions collection used
elsewhere in this module) and assign that result to TOTAL_RULES_PER_CATEGORY (or
a new derived constant) so density/diversity calculations use the real
denominators; update any references in scoring functions (e.g., where
TOTAL_RULES_PER_CATEGORY is used) to use the derived counts so adding/removing
rules no longer requires manual edits.

In `@src/core/rules/behavior/overflow-behavior-unknown.test.ts`:
- Line 1: The import list in the test file unnecessarily includes makeFile;
remove makeFile from the import statement (leaving makeNode and makeContext) to
eliminate the unused import and clean up the module import for the file where
makeNode, makeContext are used.

In `@src/core/rules/behavior/wrap-behavior-unknown.test.ts`:
- Line 1: The import statement includes an unused symbol `makeFile`; update the
import at the top of the test to remove `makeFile` so only the actually used
helpers (`makeNode`, `makeContext`) are imported, keeping the import list
minimal and avoiding the unused `makeFile` identifier.

In `@src/core/rules/component/index.ts`:
- Around line 391-404: The current comparison uses the first element as baseline
(const base = fingerprints[0]) causing order-dependent counts; update the logic
in this block to compute the canonical fingerprint as the most frequent value
(mode) across fingerprints and then compute mismatched as those not equal to
that mode so mismatchCount is order-independent, then return the same object
(ruleId: variantStructureMismatchDef.id, nodeId: node.id, nodePath:
context.path.join(" > "), message using node.name) but with the corrected
mismatchCount/totalVariants values.

In `@src/core/rules/component/variant-structure-mismatch.test.ts`:
- Line 1: The import list at the top includes an unused symbol `makeFile`;
remove `makeFile` from the import statement so only the used helpers
(`makeNode`, `makeContext`) are imported; update the import in the test file
that currently references `makeNode, makeFile, makeContext` to drop `makeFile`
to eliminate the unused-import lint error.

In `@src/core/rules/structure/no-auto-layout.test.ts`:
- Line 1: The import list includes an unused symbol `makeFile` in the module
where `makeNode` and `makeContext` are used; either remove `makeFile` from the
import statement or use it in the tests (e.g., replace a helper call with
`makeFile` where appropriate). Update the import that currently reads `import {
makeNode, makeFile, makeContext }` to drop `makeFile` if it's not needed, or add
a test case that uses `makeFile` so the import is justified.

---

Outside diff comments:
In `@src/agents/orchestrator.ts`:
- Around line 174-185: runCalibrationAnalyze builds analyzeOptions from the
nodeId returned by loadFile but ignores a caller-supplied parsed.targetNodeId;
update the logic in runCalibrationAnalyze to honor parsed.targetNodeId (e.g. use
parsed.targetNodeId if present, otherwise fall back to nodeId from loadFile)
when constructing analyzeOptions before calling analyzeFile so the correct
subtree is analyzed.

In `@src/core/rules/structure/z-index-dependent-layout.test.ts`:
- Around line 4-83: Add two regression tests to cover boundary conditions: one
that constructs two children via makeNode whose overlap area is exactly 20% of
the smaller element and asserts zIndexDependentLayout.check(node, makeContext())
returns null (verifying the implementation's strict > 20% threshold), and
another that creates two children without absoluteBoundingBox properties and
asserts zIndexDependentLayout.check(...) returns null (verifying the
early-continue handling when boxA/boxB are missing); place these alongside the
existing tests referencing zIndexDependentLayout.check, makeNode, and
makeContext so future changes won't regress these cases.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2cab55c8-10d6-4a21-aae2-592e85b6ebf2

📥 Commits

Reviewing files that changed from the base of the PR and between 0abe6b1 and 59806a3.

📒 Files selected for processing (47)
  • .coderabbit.yaml
  • src/agents/analysis-agent.test.ts
  • src/agents/contracts/calibration.ts
  • src/agents/evidence-collector.test.ts
  • src/agents/gap-rule-report.test.ts
  • src/agents/orchestrator.test.ts
  • src/agents/orchestrator.ts
  • src/agents/report-generator.test.ts
  • src/cli/commands/internal/calibrate-run.ts
  • src/core/contracts/category.ts
  • src/core/contracts/rule.ts
  • src/core/engine/integration.test.ts
  • src/core/engine/rule-engine.test.ts
  • src/core/engine/scoring.test.ts
  • src/core/engine/scoring.ts
  • src/core/report-html/index.ts
  • src/core/rules/ai-readability/ambiguous-structure.test.ts
  • src/core/rules/ai-readability/empty-frame.test.ts
  • src/core/rules/ai-readability/index.ts
  • src/core/rules/ai-readability/invisible-layer.test.ts
  • src/core/rules/ai-readability/missing-layout-hint.test.ts
  • src/core/rules/behavior/index.ts
  • src/core/rules/behavior/overflow-behavior-unknown.test.ts
  • src/core/rules/behavior/prototype-link-in-design.test.ts
  • src/core/rules/behavior/text-truncation-unhandled.test.ts
  • src/core/rules/behavior/wrap-behavior-unknown.test.ts
  • src/core/rules/component/index.ts
  • src/core/rules/component/variant-structure-mismatch.test.ts
  • src/core/rules/custom/custom-rule-loader.test.ts
  • src/core/rules/handoff-risk/hardcode-risk.test.ts
  • src/core/rules/handoff-risk/prototype-link-in-design.test.ts
  • src/core/rules/index.ts
  • src/core/rules/layout/absolute-position.test.ts
  • src/core/rules/layout/deep-nesting.test.ts
  • src/core/rules/layout/fixed-width-in-responsive-context.test.ts
  • src/core/rules/layout/group-usage.test.ts
  • src/core/rules/layout/index.ts
  • src/core/rules/layout/missing-responsive-behavior.test.ts
  • src/core/rules/layout/no-auto-layout.test.ts
  • src/core/rules/naming/index.ts
  • src/core/rules/rule-config.ts
  • src/core/rules/structure/index.ts
  • src/core/rules/structure/no-auto-layout.test.ts
  • src/core/rules/structure/responsive-fields.test.ts
  • src/core/rules/structure/unnecessary-node.test.ts
  • src/core/rules/structure/z-index-dependent-layout.test.ts
  • src/core/ui-constants.ts
💤 Files with no reviewable changes (15)
  • src/cli/commands/internal/calibrate-run.ts
  • src/core/rules/layout/missing-responsive-behavior.test.ts
  • src/core/rules/layout/group-usage.test.ts
  • src/core/rules/handoff-risk/hardcode-risk.test.ts
  • src/core/rules/ai-readability/missing-layout-hint.test.ts
  • src/core/rules/ai-readability/ambiguous-structure.test.ts
  • src/core/rules/handoff-risk/prototype-link-in-design.test.ts
  • src/core/rules/ai-readability/empty-frame.test.ts
  • src/core/rules/ai-readability/invisible-layer.test.ts
  • src/core/rules/layout/deep-nesting.test.ts
  • src/core/rules/layout/no-auto-layout.test.ts
  • src/core/rules/layout/absolute-position.test.ts
  • src/core/rules/layout/fixed-width-in-responsive-context.test.ts
  • src/core/rules/ai-readability/index.ts
  • src/core/rules/layout/index.ts

Comment on lines 75 to +80
const TOTAL_RULES_PER_CATEGORY: Record<Category, number> = {
layout: 8,
structure: 9,
token: 7,
component: 3,
component: 4,
naming: 5,
"ai-readability": 5,
"handoff-risk": 4,
behavior: 4,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Avoid hand-maintaining category rule totals.

These literals have to stay in sync with the registered rules. If a rule is added or removed and this map is missed, diversity percentages become silently wrong. Please derive the denominators from the rule definitions/registry at module init instead of updating them by hand.

As per coding guidelines, src/core/engine/scoring.ts: Verify density/diversity weighting logic is mathematically sound.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/engine/scoring.ts` around lines 75 - 80, TOTAL_RULES_PER_CATEGORY is
hard-coded and can get out of sync with the actual registered rules; replace the
manual map by computing per-category counts at module initialization from the
authoritative rule registry (e.g., iterate the registered rules/definitions
collection used elsewhere in this module) and assign that result to
TOTAL_RULES_PER_CATEGORY (or a new derived constant) so density/diversity
calculations use the real denominators; update any references in scoring
functions (e.g., where TOTAL_RULES_PER_CATEGORY is used) to use the derived
counts so adding/removing rules no longer requires manual edits.

@@ -0,0 +1,89 @@
import { makeNode, makeFile, makeContext } from "../test-helpers.js";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Unused import: makeFile

The makeFile helper is imported but never used in this test file.

🧹 Proposed fix
-import { makeNode, makeFile, makeContext } from "../test-helpers.js";
+import { makeNode, makeContext } from "../test-helpers.js";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { makeNode, makeFile, makeContext } from "../test-helpers.js";
import { makeNode, makeContext } from "../test-helpers.js";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/rules/behavior/overflow-behavior-unknown.test.ts` at line 1, The
import list in the test file unnecessarily includes makeFile; remove makeFile
from the import statement (leaving makeNode and makeContext) to eliminate the
unused import and clean up the module import for the file where makeNode,
makeContext are used.

@@ -0,0 +1,121 @@
import { makeNode, makeFile, makeContext } from "../test-helpers.js";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Unused import: makeFile

The makeFile helper is imported but never used in this test file.

🧹 Proposed fix
-import { makeNode, makeFile, makeContext } from "../test-helpers.js";
+import { makeNode, makeContext } from "../test-helpers.js";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { makeNode, makeFile, makeContext } from "../test-helpers.js";
import { makeNode, makeContext } from "../test-helpers.js";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/rules/behavior/wrap-behavior-unknown.test.ts` at line 1, The import
statement includes an unused symbol `makeFile`; update the import at the top of
the test to remove `makeFile` so only the actually used helpers (`makeNode`,
`makeContext`) are imported, keeping the import list minimal and avoiding the
unused `makeFile` identifier.

Comment on lines +391 to +404
// Compare all fingerprints to the first one
const base = fingerprints[0];
const mismatched = fingerprints.filter(fp => fp !== base);

if (mismatched.length === 0) return null;

const mismatchCount = mismatched.length;
const totalVariants = fingerprints.length;

return {
ruleId: variantStructureMismatchDef.id,
nodeId: node.id,
nodePath: context.path.join(" > "),
message: `"${node.name}" has ${mismatchCount}/${totalVariants} variants with different child structures — AI cannot create a unified component template`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Make the mismatch count independent of variant order.

Line 392 uses the first variant as the baseline. For fingerprints like [A, B, B], this reports 2/3 mismatches if the outlier happens to be first, and 1/3 if it is not. The issue itself is valid, but the reported count becomes order-dependent and can overstate divergence.

🔧 Suggested fix
-  // Compare all fingerprints to the first one
-  const base = fingerprints[0];
-  const mismatched = fingerprints.filter(fp => fp !== base);
-
-  if (mismatched.length === 0) return null;
-
-  const mismatchCount = mismatched.length;
+  const fingerprintCounts = new Map<string, number>();
+  let dominantCount = 0;
+  for (const fingerprint of fingerprints) {
+    const nextCount = (fingerprintCounts.get(fingerprint) ?? 0) + 1;
+    fingerprintCounts.set(fingerprint, nextCount);
+    if (nextCount > dominantCount) dominantCount = nextCount;
+  }
+
+  const mismatchCount = fingerprints.length - dominantCount;
+  if (mismatchCount === 0) return null;
   const totalVariants = fingerprints.length;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/rules/component/index.ts` around lines 391 - 404, The current
comparison uses the first element as baseline (const base = fingerprints[0])
causing order-dependent counts; update the logic in this block to compute the
canonical fingerprint as the most frequent value (mode) across fingerprints and
then compute mismatched as those not equal to that mode so mismatchCount is
order-independent, then return the same object (ruleId:
variantStructureMismatchDef.id, nodeId: node.id, nodePath: context.path.join(" >
"), message using node.name) but with the corrected mismatchCount/totalVariants
values.

@@ -0,0 +1,95 @@
import { makeNode, makeFile, makeContext } from "../test-helpers.js";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Unused import: makeFile

The makeFile helper is imported but never used in this test file.

🧹 Proposed fix
-import { makeNode, makeFile, makeContext } from "../test-helpers.js";
+import { makeNode, makeContext } from "../test-helpers.js";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { makeNode, makeFile, makeContext } from "../test-helpers.js";
import { makeNode, makeContext } from "../test-helpers.js";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/rules/component/variant-structure-mismatch.test.ts` at line 1, The
import list at the top includes an unused symbol `makeFile`; remove `makeFile`
from the import statement so only the used helpers (`makeNode`, `makeContext`)
are imported; update the import in the test file that currently references
`makeNode, makeFile, makeContext` to drop `makeFile` to eliminate the
unused-import lint error.

@@ -0,0 +1,140 @@
import { makeNode, makeFile, makeContext } from "../test-helpers.js";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Unused import: makeFile

The makeFile helper is imported but never used in this test file.

🧹 Proposed fix
-import { makeNode, makeFile, makeContext } from "../test-helpers.js";
+import { makeNode, makeContext } from "../test-helpers.js";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { makeNode, makeFile, makeContext } from "../test-helpers.js";
import { makeNode, makeContext } from "../test-helpers.js";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/rules/structure/no-auto-layout.test.ts` at line 1, The import list
includes an unused symbol `makeFile` in the module where `makeNode` and
`makeContext` are used; either remove `makeFile` from the import statement or
use it in the tests (e.g., replace a helper call with `makeFile` where
appropriate). Update the import that currently reads `import { makeNode,
makeFile, makeContext }` to drop `makeFile` if it's not needed, or add a test
case that uses `makeFile` so the import is justified.

@let-sunny let-sunny merged commit 338c7dc into main Mar 25, 2026
3 checks passed
@let-sunny let-sunny deleted the fix/calibration-cli-issues-63 branch March 25, 2026 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

chore: 내부 캘리브레이션 커맨드 및 list-rules 소소한 개선

1 participant