Skip to content

fix(web): resolve 2xl layout, section sorting, security hardening, and bundle footprint - #276

Merged
williamzujkowski merged 2 commits into
mainfrom
feat/qa-ux-improvements
Oct 6, 2026
Merged

williamzujkowski merged 2 commits into
mainfrom
feat/qa-ux-improvements

Conversation

@williamzujkowski

Copy link
Copy Markdown
Collaborator

Summary

This PR addresses P0 and P1 review findings across QA, Legal Accuracy, Security, and Code Optimization audits.

1. QA & UX Readability Enhancements

  • Fix 2XL Viewport Distortion: In BaseLayout.astro, restructured the layout container so that <footer> remains a full-width bottom child across all responsive viewports, resolving the issue where viewports >= 1536px rendered the footer as a vertical column beside the article.
  • ReadingToolbar Resiliency: Added try/catch guards around localStorage access in ReadingToolbar.svelte, scoped the class mutator to statutory content, and boosted label contrast (text-slate dark:text-gray-300) to achieve WCAG AA contrast.
  • Dark Mode Contrast: Added --color-amber: #FFBE2E in dark mode inside global.css for >8:1 contrast on deep navy.
  • Git Hunk Headers: Stripped @@ -x,y +x,y @@ hunk markers and leading context spaces in github.ts.
  • Interactive Form Controls: Guarded SELECT elements and isContentEditable in the j / k keyboard navigation listener.

2. Legal Accuracy

  • Eliminate parseFloat Section Sorting Bug: JavaScript's parseFloat('2000e-1') evaluates hyphens as scientific notation (200), corrupting the order of Title 42 Civil Rights sections and sections with letter suffixes (e.g. 101a). Implemented and exported compareSectionNumbers in @civic-source/shared, backed by comprehensive test coverage, and adopted it across the web app.
  • Annotation Path Section Symbol: Updated regex in annotator.ts to accept optional § and whitespace so citations like 18 U.S.C. § 111 resolve to canonical paths.
  • SummaryBox Renumbered Status: Added support for renumbered statutes in SummaryBox.astro to prevent false 'In Force' badges.

3. Security Hardening

  • CSP Directives: Added base-uri 'self'; object-src 'none'; form-action 'self'; to BaseLayout.astro.
  • DOM XSS Defense: Replaced wrapper.innerHTML = prose.innerHTML in chapter.astro with document.adoptNode.
  • Query Parameter Sanitization: Stripped double quotes and backslashes in CourtListener API query construction and URL-encoded query parameters.
  • Empty Source URL Validation: Added OptionalHttpUrlSchema in @civic-source/types so off-origin CourtListener URLs falling back to '' do not abort the annotation pipeline.
  • ZIP Bomb Bound: Reduced MAX_DECOMPRESSED_BYTES in @civic-source/fetcher to 500 MiB to strictly remain within V8 MAX_STRING_LENGTH (~512 MB).
  • Network Retry Jitter: Added randomized full jitter to exponential backoff delays in @civic-source/shared to mitigate thundering herds.

4. Performance & Bundle Footprint

  • Decoupled Client Search Bundle: Extracted sanitizeExcerpt into sanitize.ts, preventing SearchBar.svelte from importing @octokit/rest and cutting ~255 KB of unnecessary JavaScript from every page load.
  • Test Build Acceleration: Excluded src/__tests__ in tsconfig.build.json across packages, halving Vitest execution time by preventing redundant double runs on dist/.

Verification

  • pnpm -r test passed 100% across all 6 packages.
  • pnpm -r typecheck passed with 0 errors across 20 files.
  • pnpm run lint passed across all packages.
  • pnpm build succeeded cleanly.
  • pnpm audit reports 0 known vulnerabilities.

…d bundle footprint

- Fix 2xl viewport layout distortion in BaseLayout.astro by anchoring footer as a full-width bottom child
- Resolve section sorting bug (parseFloat evaluating Title 42 Section 2000e-1 in scientific notation) with compareSectionNumbers
- Harden CSP with base-uri, object-src, and form-action directives
- Replace chapter full-text innerHTML DOM assignment with document.adoptNode
- Add --color-amber dark mode token (#FFBE2E) for WCAG AA contrast on navy
- Decouple sanitizeExcerpt into sanitize.ts to prevent bundling Octokit on every page
- Add OptionalHttpUrlSchema to avoid crashing on empty or unpinned CourtListener source URLs
- Cap MAX_DECOMPRESSED_BYTES to 500 MiB within V8 MAX_STRING_LENGTH
- Add randomized jitter to retry exponential backoff
- Exclude src/__tests__ from tsconfig.build.json across packages to speed up Vitest
@williamzujkowski
williamzujkowski requested a review from a team as a code owner October 6, 2026 13:33
Comment thread packages/annotator/src/annotator.ts Fixed
const match = /^(\d+[a-zA-Z]?)\s+U\.S\.C\.\s+(\d+[a-zA-Z-]*)$/.exec(section);
// Pre-normalize section symbols and collapse multiple whitespace runs
// to avoid polynomial catastrophic backtracking (ReDoS) on untrusted input
const normalized = section.replace(/[§\u00A7]|&sect;/g, ' ').trim().replace(/\s+/g, ' ');
@williamzujkowski
williamzujkowski merged commit 96addf4 into main Oct 6, 2026
3 checks passed
@williamzujkowski
williamzujkowski deleted the feat/qa-ux-improvements branch October 6, 2026 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants