-
Notifications
You must be signed in to change notification settings - Fork 0
refactor(css): Phase 2 closed on evidence — FL extraction rejected, orphan cleanup + bundle merge shipped (-2,553 lines) #363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5892fe4
09cfce2
11a9784
88b344f
821b0d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| # CSS Maintainability Redesign — approved spec (2026-07-12) | ||
|
|
||
| Supersedes Phase 3 (WP3.1–3.4) of the original migration plan. Approved by Paul on | ||
| 2026-07-12 after per-section review (brainstorming session, sprint 7). | ||
|
|
||
| ## Why the plan changed | ||
|
|
||
| The original goal — "eliminate 70-80% CSS duplication (27,094–31,536 lines)" — was | ||
| falsified twice. Phase 1 measurement (WP1.2/WP1.4) and the Phase 2 audits both showed | ||
| that in this pipeline PurgeCSS runs per bundle, so each page already ships only its own | ||
| subset; consolidating source files grows shipped bytes (measured: shared FL foundation | ||
| = +7.1–9.8 KB gzip first-visit per page). Line counts of source files predict nothing. | ||
|
|
||
| The real pain, named by Paul: **fear of cross-page breakage** — nobody can tell which | ||
| pages a CSS edit affects, and ~75K lines of generated FL-Builder export CSS | ||
| (`.fl-node-*` rules keyed to hash IDs) are effectively obfuscated and un-editable. | ||
|
|
||
| ## Goal | ||
|
|
||
| Every style on the site is **hand-editable, understood, and single-source**. | ||
| FL-Builder export CSS is a legacy liability to retire page-by-page (strangler | ||
| pattern), not to optimize in place. | ||
|
|
||
| ### Success criteria | ||
|
|
||
| 1. **FL retirement burn-down**: live FL layout files 17 → 0. Each rewritten page | ||
| deletes its FL CSS file(s) and its template's `fl-node-*` markup in the same PR. | ||
| 2. **No obfuscated artifacts** at end state: zero hash-named CSS files | ||
| (`bf72bba…`, `e966db44…`, `fb2624…`), zero generated node-id rules. | ||
| 3. **No duplication in the hand-maintained layer**: new CSS uses tokens from | ||
| `foundations/css-variables.css` and shared components; the same rule appearing | ||
| twice is a defect. | ||
| 4. **Safe-edit guarantee**: for any CSS file, "which pages does this affect?" is | ||
| answerable in under a minute (ownership map + per-file header), and the existing | ||
| test suites (`bin/test` + `bin/dtest`) verify a change end-to-end. | ||
| 5. **Evidence rule**: any size/perf claim is validated on compiled + gzip per-page | ||
| payload, never raw source line counts. | ||
|
|
||
| ### Non-goals | ||
|
|
||
| - Transfer-size optimization (proven net-negative territory here). | ||
| - Consolidating, renaming, or refurbishing FL files that are scheduled to die. | ||
| - PostCSS pipeline changes, except where a rewrite requires one. | ||
|
|
||
| ## Phase 0 — safety scaffolding (one small sprint, before any rewrite) | ||
|
|
||
| Regression detection uses the EXISTING snapdiff infrastructure — `bin/test` (macOS) | ||
| and `bin/dtest` (Linux/Docker), built on capybara_screenshot_diff with | ||
| `FORCE_SCREENSHOT_UPDATE=true` for baseline regeneration and | ||
| `SCREENSHOT_STABILITY_TIME` for flaky pages. **No new custom baseline/compare | ||
| scripts.** Where the suites don't cover a surface, the fix is adding tests, not | ||
| tooling. Phase 0 closes the known coverage gaps: | ||
|
|
||
| 1. **Special-content blog post coverage.** Blog posts exercise CSS surfaces no | ||
| marketing page touches, and today only one post (red-flags…) is screenshot-tested. | ||
| Inventory findings (2026-07-12): 3 posts use Mermaid diagrams | ||
| (langchain-memory-systems…, rails-performance-at-scale…, hidden-cost-poor- | ||
| development…), 139 posts have Chroma-highlighted code fences, 3 posts carry raw | ||
| inline `style=` HTML, and the `youtube` shortcode is in use. Add desktop + mobile | ||
| screenshot tests for one representative post per surface: a Mermaid post, a | ||
| code-highlight-heavy post (Dracula wrapper must render), an inline-style post, | ||
| and a youtube-embed post. The skipped `DiagramComponentTest` | ||
| (test/system/components/diagram_component_test.rb) gets revived or replaced by | ||
| the Mermaid-post test. | ||
| 2. **Rewrite-target coverage check.** Before each page's rewrite sprint, confirm the | ||
| suites screenshot that page (desktop + mobile); add the missing test first if not. | ||
| 3. **Page→bundle ownership map** — one doc in this folder listing all 19 bundles: | ||
| owning template, feeding CSS files, URLs that load it, current gzip size, rewrite | ||
| status (live-FL / rewritten / retired). Doubles as the burn-down chart. Each FL | ||
| CSS file gets a one-line header comment pointing at the map. | ||
| 4. **Orphan guard** — a check that lists CSS files under `themes/beaver/assets/css/` | ||
| referenced by no template resource slice, so dead files can't accumulate again. | ||
|
|
||
| No legacy CSS edits in Phase 0. | ||
|
|
||
| ## The per-page rewrite protocol (repeating unit; one page, one branch, one PR) | ||
|
|
||
| 1. **Capture the before**: confirm the page has snapdiff coverage (add the test if | ||
| missing — Phase 0 item 2), regenerate its baselines | ||
| (`FORCE_SCREENSHOT_UPDATE=true`) on both suites; full-page screenshots at | ||
| 1280×800 and 390×844 as the design reference. | ||
| 2. **Design pass**: start from `.stitch/design.md` (JetVelocity). Visual improvement | ||
| is allowed and expected; write a short layout-intent note (what stays, what | ||
| modernizes). Review includes a scored design-critic pass against external anchors, | ||
| not just a defect checklist. | ||
| 3. **Rewrite the template**: semantic HTML, no `fl-node-*` / `fl-row` / `fl-col` | ||
| classes; class names carry meaning (`clients-hero`, `cta-banner`). Shared partials | ||
| (header/nav/footer, technologies, testimonials) stay untouched until their own turn. | ||
| 4. **Write the page CSS**: one file per page under `css/pages/`, built on | ||
| `css-variables.css` tokens; no literal value where a token exists. Target hundreds | ||
| of lines, not thousands. Swap the resource slice: FL files out, new file in. | ||
| 5. **Delete in the same PR**: the page's FL layout CSS plus any satellite that loses | ||
| its last importer. Orphan guard confirms. | ||
| 6. **Verify**: | ||
| - Both visual suites (`bin/test` macOS + `bin/dtest` Linux): this page's | ||
| baselines change intentionally and are updated in the PR (both macos/ AND | ||
| linux/) after Paul approves; every OTHER page and every special-content blog | ||
| screenshot must be 0.0-diff — that is the no-cross-page-breakage guarantee. | ||
| - Chrome DevTools: zero console errors, zero 404s; desktop + mobile screenshots | ||
| attached to the PR for design approval. | ||
| 7. **Rule of three**: extract a shared component to `css/components/` only when a | ||
| 2nd–3rd rewritten page needs a pattern an earlier one has; the extraction PR | ||
| touches only rewritten pages and is verified the same way. | ||
|
|
||
| Rollback = revert one PR; the FL file returns. | ||
|
|
||
| ## Rewrite order (easiest first, ascending FL size) | ||
|
|
||
| | # | Page (FL file) | FL lines | | ||
| |---|----------------|----------| | ||
| | 1 | Generic pages + course list (3059) | 924 | | ||
| | 2 | Contact-us (706) | 2,202 | | ||
| | 3 | Blog/client/career/course singles (3114) | 2,272 | | ||
| | 4 | Free-consultation + blog lists (homepage-layout + services-layout satellites) | ~4,356 | | ||
| | 5 | Career single (e966db44…) | 4,364 | | ||
| | 6 | About (701) | 4,462 | | ||
| | 7→ | Use-cases single (3027), careers (3086-layout2), clients landing (3082), services single (2949), use-cases landing (3021), clients single (fb2624…), services landing (737) — ascending | 5,056–6,523 | | ||
| | last | Homepage (590) | 12,437 | | ||
|
|
||
| The shared `bf72bba…` bundle (8 templates) and the `critical/` FL trio retire when | ||
| their last consumer is rewritten. Order flexes when Paul wants a page modernized | ||
| sooner; the protocol never changes. | ||
|
|
||
| ## Bookkeeping | ||
|
|
||
| - Old Phase 3 (pattern consolidation + Hugo enhancements, 20–45 h) is **closed as | ||
| superseded** — its premise died with the compiled+gzip evidence. | ||
| - TASK-TRACKER updates: GOAL OVERVIEW rewritten to this goal; stale CUMULATIVE | ||
| METRICS replaced by the FL burn-down table (17 → 0); new phases = Phase 0 | ||
| (scaffolding) then rewrite sprints R1…Rn. | ||
| - Pace: one page per sprint, no fixed calendar. One branch + one bundled PR per | ||
| sprint, per repo policy. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,11 +26,11 @@ | |
|
|
||
| ``` | ||
| Phase 1: Critical CSS Inline [✅❌✅❌] 4/4 WPs resolved (2 done, 2 closed with evidence) | ||
| Phase 2: FL-Builder Foundations [🔲🔲🔲🔲] 0/4 WPs (0% complete) | ||
| Phase 2: FL-Builder Foundations [❌❌❌❌] 4/4 WPs resolved (all closed with evidence; cleanup shipped instead) | ||
| Phase 3: Additional Patterns [🔲🔲🔲🔲] 0/4 WPs (0% complete) | ||
|
|
||
| Total Progress: 4/12 work packages resolved | ||
| Lines Eliminated: ~70,600 (sprints 1-6; orphan deletion + consolidation) | ||
| Total Progress: 8/12 work packages resolved | ||
| Lines Eliminated: ~73,150 (sprints 1-7; orphan deletion + consolidation) | ||
| ``` | ||
|
|
||
| **Status Legend**: | ||
|
|
@@ -239,16 +239,22 @@ notes: | | |
|
|
||
| ## 📅 PHASE 2: FL-Builder Foundation Extraction | ||
|
|
||
| **Phase Status**: 🔲 Not Started | ||
| **Duration**: 40-50 hours (4-5 weeks part-time) | ||
| **Target Impact**: 1,900-2,900 lines eliminated | ||
| **Risk Level**: MEDIUM - Systematic extraction from 7 files | ||
| **Phase Status**: ❌ CLOSED 2026-07-12 (sprint 7) — extraction rejected on measurement; orphan cleanup + bundle merge shipped instead | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Replace em dashes with hyphens. These changed Markdown lines use Also applies to: 255-255, 283-283, 311-311, 339-339, 369-371, 601-601 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
| **Original Target**: 1,900-2,900 lines eliminated via shared FL foundations | ||
| **Why closed** (two independent read-only audits against the compiled production baseline): | ||
| - The spec's "7 FL-Builder layout files" is stale: **17 live layout files**, all external `<link>` bundles via `css-processor.html`, none inline. | ||
| - The proposed foundation files **already existed as never-wired orphans** (utilities/fl-builder-*, components/layout-*, foundations/_fl-responsive-display.scss — a .scss file in a Sass-less PostCSS pipeline). Deleted in sprint 7. | ||
| - **Shipped-byte math is net-NEGATIVE**: each page loads exactly one PurgeCSS-purged bundle carrying only its own FL subset. A shared foundation must carry the union of all 979 unique FL rules (120KB raw / 11.3KB gz): first-visit +7.1KB gz (homepage) to +9.8KB gz (blog list) per page. Multi-page warm-cache session saves only ~1.5KB gz total across 4 pages. | ||
| - The `.fl-visible` "90-95% duplication" claim measured at **41.9%** across bundles (453 instances, 263 distinct — high per-bundle counts are distinct breakpoint variants, not copies). | ||
| - ~7,991 of 75,382 layout-file lines are per-page `fl-node-XXXX` rules that extraction cannot consolidate by definition; the byte-identical generic blocks are only a few hundred lines and already deduped per-bundle at build time by postcss-delete-duplicate-css. | ||
|
|
||
| Same lesson as WP1.4: verify projected savings against COMPILED + GZIPPED output, not source line counts. | ||
|
|
||
| ### Work Package Status | ||
|
|
||
| #### WP2.1: FL-Row Foundation Extraction 🔲 NOT STARTED | ||
| #### WP2.1: FL-Row Foundation Extraction ❌ CLOSED — net-negative on shipped bytes (see Phase header) | ||
| ```yaml | ||
| status: 🔲 Not Started | ||
| status: ❌ Closed 2026-07-12 without implementation (sprint 7 measurement) | ||
|
Comment on lines
+255
to
+257
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Mark the closed work-package tasks as superseded. These headings now say the work packages closed without implementation, but their following task lists remain unchecked and read like active work. Mark them as not applicable/superseded or move the historical plans into an archive section. Also applies to: 283-285, 311-313, 339-341 🤖 Prompt for AI Agents |
||
| priority: P0 🔥 Critical | ||
| duration: 12-16 hours | ||
| files_affected: 7 FL-Builder layout files | ||
|
|
@@ -274,9 +280,9 @@ actual_commits: - | |
| notes: Largest single pattern extraction in project | ||
| ``` | ||
|
|
||
| #### WP2.2: FL-Col Grid Foundation 🔲 NOT STARTED | ||
| #### WP2.2: FL-Col Grid Foundation ❌ CLOSED — net-negative on shipped bytes (see Phase header) | ||
| ```yaml | ||
| status: 🔲 Not Started | ||
| status: ❌ Closed 2026-07-12 without implementation (sprint 7 measurement) | ||
| priority: P0 🔥 Critical | ||
| duration: 10-14 hours | ||
| files_affected: 7 FL-Builder layout files | ||
|
|
@@ -302,9 +308,9 @@ actual_commits: - | |
| notes: Grid system must maintain responsive behavior | ||
| ``` | ||
|
|
||
| #### WP2.3: FL-Visible Responsive Foundation 🔲 NOT STARTED | ||
| #### WP2.3: FL-Visible Responsive Foundation ❌ CLOSED — duplication claim falsified (41.9%, not 90-95%) | ||
| ```yaml | ||
| status: 🔲 Not Started | ||
| status: ❌ Closed 2026-07-12 without implementation (sprint 7 measurement) | ||
| priority: P0 🔥 Critical | ||
| duration: 10-14 hours | ||
| files_affected: 7 FL-Builder layout files | ||
|
|
@@ -330,9 +336,9 @@ actual_commits: - | |
| notes: Highest duplication percentage (90-95%) | ||
| ``` | ||
|
|
||
| #### WP2.4: Foundation Integration & Validation 🔲 NOT STARTED | ||
| #### WP2.4: Foundation Integration & Validation ❌ CLOSED — moot (no foundations to integrate; WP2.1-2.3 closed) | ||
| ```yaml | ||
| status: 🔲 Not Started | ||
| status: ❌ Closed 2026-07-12 (sprint 7) | ||
| priority: P0 🔥 Critical | ||
| duration: 8-10 hours | ||
| files_affected: All 7 FL-Builder layout files + 3 foundation files | ||
|
|
@@ -360,15 +366,13 @@ notes: Phase 2 gate - must pass all validations | |
| ### Phase 2 Summary | ||
| ```yaml | ||
| work_packages_total: 4 | ||
| work_packages_completed: 0 | ||
| work_packages_blocked: 0 | ||
| total_duration_target: 40-50 hours | ||
| total_duration_actual: 0 hours | ||
| total_lines_eliminated_target: 1,900-2,900 lines | ||
| total_lines_eliminated_actual: 0 lines | ||
| total_commits_target: 100-135 commits | ||
| total_commits_actual: 0 commits | ||
| foundation_files_created: 0 / 3 (_fl-row, _fl-col, _fl-responsive-display) | ||
| work_packages_completed: 0 (all 4 closed with evidence, no extraction implemented) | ||
| phase_status: CLOSED 2026-07-12 (sprint 7) | ||
| foundation_files_created: 0 — and the 6 pre-existing never-wired foundation orphans were DELETED | ||
| shipped_instead: | ||
| - deleted 6 orphan artifacts + 61 stale comment refs (-597 lines, compiled output byte-identical) | ||
| - merged e93d9b85…-layout-bundle.css into its superset bf72bba… (-1,956 lines, compiled output byte-identical; clients page purges the 2 extra rules) | ||
| lesson: same as WP1.4 — savings claims must be verified against compiled+gzipped bundles; PurgeCSS-per-bundle already gives each page its minimal FL subset, so shared foundations regress first-visit transfer size | ||
| ``` | ||
|
|
||
| --- | ||
|
|
@@ -516,7 +520,7 @@ foundation_files_created: 0 / 2 (_fl-backgrounds, _fl-imports) | |
| ```yaml | ||
| phase_1_blockers: NONE - Ready to start immediately | ||
| phase_2_blockers: NONE - Waiting for Phase 1 completion | ||
| phase_3_blockers: NONE - Waiting for Phase 2 completion | ||
| phase_3_blockers: NONE - Phase 2 closed 2026-07-12; Phase 3 WPs must be re-scoped against compiled+gzip output BEFORE any work starts (Phase 1+2 both falsified their specs) | ||
|
Comment on lines
521
to
+523
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Update the stale Phase 2 blocker status. Line [522] still says Phase 2 is “Waiting for Phase 1 completion,” while Lines [242] and [370] state that Phase 2 closed on July 12, 2026. Change this to reflect the closed state. 🤖 Prompt for AI Agents |
||
|
|
||
| critical_path_risks: NONE - All dependencies clear | ||
| ``` | ||
|
|
@@ -594,6 +598,39 @@ fcp_metrics: | |
|
|
||
| ## 🔄 UPDATE LOG | ||
|
|
||
| ### 2026-07-12 (sprint 7 — Phase 2 re-scoped and closed) | ||
|
|
||
| Swarm protocol: two parallel read-only auditors (source inventory + compiled-output | ||
| measurement against a converged production baseline); all mutations sequential in the | ||
| main loop under the byte-diff gate + both visual suites per commit. | ||
|
|
||
| **Evidence (falsified the Oct-2025 Phase 2 spec on every load-bearing claim):** | ||
| - 17 live layout files (not 7), all external bundles, mapped file→template→page. | ||
| - Proposed foundation destinations already existed as 6 never-wired orphans, one of them | ||
| `.scss` in a Sass-less pipeline. The Oct plan was half-built, abandoned, and never loaded. | ||
| - Cross-source duplication per page < 1KB raw (FL portion ≈ 0); careers (worst page) | ||
| perfect-dedup saves 310 bytes gz. The 201KB "redundancy" spans 19 page-type bundles a | ||
| visitor never co-loads. | ||
| - Shared-foundation simulation: first-visit +7.1 to +9.8KB gz per page (PurgeCSS already | ||
| ships per-page minimal subsets; union foundation = 120KB raw / 11.3KB gz unpurged). | ||
| - `.fl-visible` duplication 41.9% measured vs 90-95% claimed. | ||
|
|
||
| **Shipped:** | ||
| - 5892fe44 — deleted 6 orphan FL-foundation artifacts + 61 stale comment refs | ||
| (-597 lines). Gate: all compiled bundles byte-identical; HTML diffs = known noise only | ||
| (sw.js?v= stamp, taxonomy term-casing race). macOS 46/46 + 84 screenshots clean; | ||
| Linux dtest 46/46. | ||
| - (this commit) — merged `e93d9b85…-layout-bundle.css` (1,956 lines) into its superset | ||
| `bf72bba…` (13-line diff: img.mfp-img padding + fl-photo @860px block) by repointing | ||
| `page/clients.html`. Compiled output 100% byte-identical (PurgeCSS drops the 2 extra | ||
| rules for clients; clients page has zero mfp-img/fl-photo elements). Both suites green. | ||
|
Comment on lines
+623
to
+626
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Use a stable commit identifier instead of “this commit.” The update log should record the actual commit hash or a stable label; “this commit” becomes ambiguous after subsequent commits are added. 🤖 Prompt for AI Agents |
||
|
|
||
| **Not done / follow-ups:** Phase 3 specs carry the same Oct-2025 line-count methodology — | ||
| re-scope against compiled+gzip before starting. `fl-builder-common-base.css` and | ||
| `utilities/fl-builder-grid.css` are single-importer live files (fold-in candidates for a | ||
| later sprint). Near-dupe cohort analysis (12 numbered files vs 4 hash bundles) done, no | ||
| further whole-file merges found. | ||
|
|
||
| ### 2026-07-12 (sprint 6 continuation — WP1 / Phase 1 closed) | ||
| - **Landed** (same branch/PR #360, 7 more commits): Phase 1 fully resolved. | ||
| 1. 23ed3049 — WP1.3 done: 6 duplicated infobox blocks in | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Replace em dashes with hyphens.
Line [1], Line [45], and Line [111] use
—, which violates the Markdown content guideline. Use-instead.Also applies to: 45-45, 111-112
🤖 Prompt for AI Agents
Source: Coding guidelines