type: rule
status: active
timestamp: 2026-06-21
tags: [rules, design-system, dedup, packages, components]

Design divergence is NOT duplication

Per-app design divergence, not duplication

Design divergence is NOT duplication

2026-06-22 update (sweep #5). This rule was correct all along but was violated by sweep #3 (which deleted vendored Header/Footer/Wordmark.astro from 9 apps in favour of @chirag127/astro-chrome shared components) and sweep #4 (which extended the consolidation through Layout.astro). The user grilled the policy on 2026-06-22 (Q1-Q8) and locked the following:

SurfacePolicy
HeaderFully divergent per-app — restore local Header.astro per app
WordmarkFully divergent per-app — restore local Wordmark.astro per app
SidebarSame CSS/drawer structure from package, per-app slot content
FooterIdentical mega-sitemap family-wide — only true consolidation; keep package import
BottomBarSame CSS structure from package, per-app actions prop

Sweep #5 (2026-06-22) reverted the per-app chrome loss across 10 apps while keeping the Footer + BottomBar structural consolidation. Footer is the only surface that is fully consolidated; the others are structurally consolidated but content-divergent.

The dedup-sweep threshold for extracting shared code into an @chirag127/* package is ≥25 lines duplicated across ≥3 consumers AND no community library covers it (see the-23-packages).

That threshold applies to TRUE duplicates — byte-identical or trivially-parameterisable code. It does NOT apply to components that share a name but implement a different design brief per app.

Components currently kept per-app on purpose

ComponentWhy divergent
HeaderEach app’s nav, logo treatment, and mode (sticky / static / translucent) is part of its design brief. hub’s broadsheet, blog’s HeaderControls, tools’ category tabs are all different.
WordmarkPer-app brand stamp (“ORIZ · pdf”, “ORIZ · paisa”, etc.) per datasheet-dark
AppSidebarContentThe Sidebar drawer/CSS comes from the package, but the content slotted into it is per-app (finance nav, PDF tools list, hub family mega-nav, etc.)
bottomBarActionsThe BottomBar shell comes from the package, but the 4-5 actions are per-app
blog’s MultiSearchBlog-specific search providers + result formatting; not a fit for the kit’s generic <MultiSearch />
blog’s astro.configBlog uses @astrojs/mdx + RSS plugins others don’t need

Components consolidated family-wide

ComponentWhy identical
FooterMega-sitemap is identical across every app — same apps list, same books list, same packages list, same legal/support links. The single true consolidation.
Sidebar.astro (shell)Drawer + responsive logic is the same; only the slotted content varies.
BottomBar.astro (shell)56px fixed-bottom mobile bar is the same; only the actions array varies.

When unification would cost more than divergence

A generic slot-based component (<Header><slot name="logo"/><slot name="nav"/></Header>) with N apps each supplying a slot config can easily be larger than the N variants combined — once you count the slot wiring, prop drilling, and per-app config files. The unified component “wins” only when the variants are mostly identical and the divergence is data-shaped (text strings, link arrays). When the divergence is layout-shaped (different DOM structure per app), keep the variants.

Heuristic before forcing consolidation

  1. Diff the candidates line-by-line. If <25 lines repeat literally across <3 apps, do not consolidate.
  2. Estimate the slot-API line count. If (slot wiring + per-app configs) ≥ Σ(variants), the consolidation is a net loss.
  3. Check the design brief. If the per-app design brief actually specifies a different layout, the divergence is the feature.

See also


Edit on GitHub · Back to index