Problem
Two dimensions in repo_tests/frontend_fragmentation_ratchet_test.py, and one in frontend_api_contract_ratchet_test.py, count size rather than duplication. Combined with the both-directions assertion they act as a cap, not a ratchet: any legitimate new component fails them, and the only way to pass is to delete something else.
| dimension |
counts |
grows when |
distinct_class_names |
unique .foo-bar names |
a new component introduces any new class |
css_rule_declarations |
total rule declarations |
same |
inline_generics |
api.*<Shape> call sites |
a new, correctly typed call is added |
This was demonstrated rather than theorised. #15429 added a load-failure banner to three views. The banner's CSS was duplicated across all three — real sprawl, correctly caught. Consolidating it into assets/main.css removed 67 lines and brought css_rule_declarations down, but distinct_class_names did not move: merging three copies into one removes declarations, not names. The five names are new UI and no consolidation removes them.
inline_generics has the same shape. The four api.get<WorkItem> calls #15429 added are correct typed detail fetches. The metric counts them as unverified assertions, which they are — but so is every correct call.
What works and should be kept
components_declaring_styles held at 381 through the same change, because styles were added to files that already had them. That is the duplication signal. The per-family counts (btn 116, status 114, …) behaved correctly too — they rise when a family gains another spelling of the same idea.
Acceptance criteria
distinct_class_names and css_rule_declarations are replaced by a measure that rises with duplication and not with legitimate growth. Candidates: rules declared in more than one file, or names differing only by a known synonym pair (modal/dialog, toast/alert).
inline_generics is replaced by, or scoped to, calls whose shape is not drawn from the generated contract — a call typed from types/generated/api.ts should not count.
- A test proves the new measure rises when the same rule is added to a second file, and does not rise when a genuinely new component is added once.
- The baselines are re-derived from the new measure, not carried over.
Notes
Until this lands the three dimensions stay, at their current figures, so they still catch a regression — they just cannot tell growth from sprawl, and anyone adding UI will have to raise them with a note. That cost is the reason to fix the measure rather than keep paying it.
Related: #12730, #12731 (the umbrella these ratchets serve), #12363, #15429 (the change that exposed this).
Problem
Two dimensions in
repo_tests/frontend_fragmentation_ratchet_test.py, and one infrontend_api_contract_ratchet_test.py, count size rather than duplication. Combined with the both-directions assertion they act as a cap, not a ratchet: any legitimate new component fails them, and the only way to pass is to delete something else.distinct_class_names.foo-barnamescss_rule_declarationsinline_genericsapi.*<Shape>call sitesThis was demonstrated rather than theorised. #15429 added a load-failure banner to three views. The banner's CSS was duplicated across all three — real sprawl, correctly caught. Consolidating it into
assets/main.cssremoved 67 lines and broughtcss_rule_declarationsdown, butdistinct_class_namesdid not move: merging three copies into one removes declarations, not names. The five names are new UI and no consolidation removes them.inline_genericshas the same shape. The fourapi.get<WorkItem>calls #15429 added are correct typed detail fetches. The metric counts them as unverified assertions, which they are — but so is every correct call.What works and should be kept
components_declaring_stylesheld at 381 through the same change, because styles were added to files that already had them. That is the duplication signal. The per-family counts (btn116,status114, …) behaved correctly too — they rise when a family gains another spelling of the same idea.Acceptance criteria
distinct_class_namesandcss_rule_declarationsare replaced by a measure that rises with duplication and not with legitimate growth. Candidates: rules declared in more than one file, or names differing only by a known synonym pair (modal/dialog,toast/alert).inline_genericsis replaced by, or scoped to, calls whose shape is not drawn from the generated contract — a call typed fromtypes/generated/api.tsshould not count.Notes
Until this lands the three dimensions stay, at their current figures, so they still catch a regression — they just cannot tell growth from sprawl, and anyone adding UI will have to raise them with a note. That cost is the reason to fix the measure rather than keep paying it.
Related: #12730, #12731 (the umbrella these ratchets serve), #12363, #15429 (the change that exposed this).