Legacy Rebrand — Streams & Cards
Four streams, scoped by concern rather than sprint. The existing token package is the canonical semantic layer. A legacy adapter layer sits on top — projecting tokens into CSS custom properties, carrying a supplement for legacy-only values, and owning the known-values manifest for safe automation.
Token Package (canonical semantic layer — unchanged)
↓
Legacy Adapter Layer (projection + supplement + manifest)
↓
CSS Variable Bundle (:root { --brand-* })
↓
App Shells (injected per app, no source changes required)
Stream 2 — Manual refactor
Shared base library Sass variables are converted to consume the CSS variable bundle. Shared components rebrand automatically across all apps that use them.
Stream 3 — PostCSS automation
App-specific hardcoded values that live outside the shared library are mechanically rewritten to var(--token, <original>) by a PostCSS plugin at build time. This covers the long tail that the manual refactor doesn’t reach.
The token package already defines semantic roles across theme variants. The work here is validating coverage against what legacy actually consumes, filling gaps via the adapter’s supplement, and authoring per-brand mapping configs.
Sprint 1
Validate token package semantic contract against legacy consumption
Audit color, typography, surface, border, and spacing roles for completeness against what pilot apps actually use. Identify gaps where legacy consumes a value that has no semantic token. Versioned gap report, committed to repo.
Sprint 1
Author legacy adapter supplement for uncovered values
Values legacy depends on that don’t have a semantic token get defined here — not in the token package. One-off grays, legacy status colors, typography values no modern component uses. If a value later proves broadly needed, it gets promoted into the token package through the normal process.
Sprint 1
Create Brand A mapping config
Brand A values mapped to semantic roles. Hand-authored with provenance comments. Every entry carries provenance: human-authored | ai-suggested | human-confirmed. Nothing ships at ai-suggested.
Sprint 1
Stub Brand B mapping config with same shape
Same schema, stubbed values pending design delivery. Validates that the mapping shape generalizes across brands.
Sprint 1
Define mapping provenance schema and review workflow
How AI-suggested mappings move to human-confirmed. Who reviews, what the gate looks like. The mapping config is the audit trail.
Sprint 1
Validate adapter output against current compiled token output without unexplained drift
Generate the CSS variable bundle from the adapter layer. Compare against the token package’s compiled output for shared roles. Any deltas must be explainable. This is the “we didn’t invent a parallel system” gate.
Sprint 4
Add CI validation for semantic mapping completeness
Every required semantic role has a mapping for every brand, or the build fails.
The adapter layer, the CSS variable bundle, and injection into each legacy app shell. The token package stays untouched. Legacy apps receive brand values as CSS custom properties at :root. The shared base library is manually refactored to consume these variables, which rebrands every shared component across all apps that use them.
Sprint 1
Inventory hardcoded values and identify per-app styling entry points
Map repeated hardcoded values across all pilot apps and document where styles get authored, bundled, and included in HTML. Feeds both the known-values manifest (Stream 3) and the injection plan.
Sprint 1
Scaffold legacy adapter layer and generate initial CSS variable bundles
Projection from token package + supplement → flat :root { --brand-* } stylesheet. One adapter, two brand outputs (Brand A live, Brand B stub).
Sprint 2
Wire CSS variable bundle into pilot app shell — smoke test
End-to-end proof the pipeline works. Inject the :root bundle into the smallest-surface app, confirm variables resolve under both brands. Go/no-go gate before broader work begins.
Sprint 2
Wire CSS variable bundle into remaining pilot app shells
Same injection pattern, applied to each remaining app.
Sprint 2
Refactor shared base library color Sass variables to CSS custom properties
Convert color-related Sass variables in the shared base library source to consume brand CSS vars. Ship color first, validate, then expand.
Sprint 2
Refactor shared base library typography and surface Sass variables to CSS custom properties
Second pass after color lands clean. Buttons, text styles, surface and border treatments.
Sprint 4
Finalize legacy brand variable naming and scoping rules
Sprint 4
Add snapshot tests for generated legacy CSS variable bundles
Lock the output shape so unintended changes are caught.
Stream 2 rebrands shared components by refactoring the base library. But every pilot app also contains hardcoded color and font values in app-specific styles that the shared library doesn’t touch. Without automation, those values stay hardcoded through the rebrand. A PostCSS plugin runs at build time in the legacy Gulp/Webpack pipeline and mechanically rewrites those values to var(--brand-token, <original-value>), making them consume the CSS variable bundle. The original value stays as a fallback — nothing breaks if the bundle fails to load. The plugin only acts on values present in a known-values manifest generated from the adapter layer; anything unmatched goes to a miss-report for human triage.
Sprint 3
Build known-values manifest from adapter layer
The only data the plugin is allowed to act on. Generated from the mapping configs and supplement, not hand-authored. Cross-checked against the inventory from Stream 2.
Sprint 3
Implement PostCSS color-to-var rewrite plugin
Two modes: report-only and commit. Walks CSS declarations, matches values against the manifest, rewrites matches to var(--token, <original>). Hand-reviewed code, not AI-merged. The plugin is small, stable, and deterministic.
Sprint 3
Run plugin in report-only mode against all pilot apps and triage miss-report
Required gate before any commit-mode run. Triage into: add to manifest, fix at source, accept as legitimate hardcode.
Sprint 3
Apply safe rewrite across pilot apps (commit mode, visual-diff gated)
Start with the highest-complexity app to stress-test the manifest. Each app gated by visual diff before merge.
Sprint 3
Triage unresolved hardcoded value hotspots
What makes it into the downstream debt report. Values that aren’t in the manifest and aren’t worth adding.
Sprint 3
Patch high-impact local overrides blocking brand uptake
Surgical, only where they block pilot success.
Sprint 3
AI-assisted mapping suggestions for long-tail miss-report entries
Claude proposes mappings with confidence scores into a review queue. Human flips to human-confirmed. Nothing auto-merges.
The safety net, the rehearsal, and the handoff artifacts that make the work durable past the rebrand cutover. Existing visual diff tooling supports snapshot, regression, and pixel-diff workflows.
Sprint 1
Capture visual QA baselines for all pilot app surfaces
Snapshot each app’s key flows. These are the “before” for every subsequent comparison.
Sprint 2
Wire visual diff as merge-blocking CI gate above pixel threshold
Without this, visual diff is documentation, not a safety net.
Sprint 2
Create brand-specific regression baselines
Sprint 2
QA shared component rendering across pilot apps
Sprint 3
Validate brand swap — rebuild pilot app under Brand B and diff against Brand A baseline
The actual rebrand rehearsal. Proves the swap works before cutover day relies on it.
Sprint 3
QA fallback behavior by intentionally breaking the variable bundle load
Verify that var(--token, <original>) degrades gracefully to the hardcoded fallback.
Sprint 3
Expand visual regression coverage for legacy flows
Sprint 4
Cross-brand regression pass on all pilot apps
Sprint 4
Browser and responsive QA sweep for shared legacy surfaces
Sprint 4
Fix QA defects from pilot rollout
Sprint 4
Document and rehearse rollback procedure
Hard-date deadline means the rollback story will be asked about. Have an answer.
Sprint 4
Document legacy consumption pattern for downstream teams
Sprint 4
Publish unresolved legacy debt report by app
Converts the “we’re not fixing all of legacy” promise into a tangible artifact each downstream team owns.
Sprint 4
Create rollout guide for additional legacy apps beyond pilot
Sprint 4
Sign off pilot rollout and downstream handoff
Critical Path / Gates
Three hard gates, in order. Missing any means stop and reassess, not push forward.
Gate 1
End of Sprint 1 — Adapter output aligns with compiled token package output without unexplained drift
If this fails, the adapter is inventing values instead of projecting them. The legacy layer must be a faithful extension of the token package, not a parallel system.
Gate 2
Early Sprint 2 — Pilot app smoke test renders correctly under both brands with the injected variable bundle
If this fails, the delivery path is wrong.
Gate 3
Mid Sprint 3 — PostCSS report-only run produces a triageable miss-report with no surprises
If the miss-report is unmanageable, scope the manifest more tightly before committing any rewrites.