Skip to content

the fragmentation ratchet's class-name and rule-count dimensions measure size, not duplication, so they cap new UI instead of ratcheting sprawl #15455

Description

@mrveiss

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

  1. 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).
  2. 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.
  3. 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.
  4. 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).

Activity

  1. added this to the Backlog milestone on Sep 12, 2026
  2. mrveiss commented on Sep 13, 2026

    @mrveiss
    OwnerAuthor

    What landed today (#16596, fcd03d0)

    Progress note for this umbrella. Checked against origin/main at b688b3e. #16596 referenced this issue (Refs). Its body says it is only a baseline move after batch 2b, not a fix for the measure.

    AC Evidence on origin/main Status
    1. Replace distinct_class_names / css_rule_declarations with a duplication measure Still the size counts: repo_tests/frontend_fragmentation_ratchet_test.py:92 (5619) and :94 (9401). #16596 changed only these two figures. ❌
    2. Scope inline_generics away from calls typed from the generated contract repo_tests/frontend_api_contract_ratchet_test.py:194 uses the same _inline_generic_count. #16596 moved its baseline 577 → 564 and reformatted two comprehensions; it did not change the measure ❌
    3. A test shows the new measure rises on a duplicated rule and not on a new component None ❌
    4. Baselines re-derived from the new measure #16596 re-derived baselines from the existing measure ❌

    What remains: all four ACs.

  3. modified the milestones: Backlog, v0.15.0 on Sep 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions