Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,39 @@
# CHANGELOG

## 2026-10-22 — Router performance gate follow-up (validated locally)

- Keep the reviewed Router 7.18.4 security candidate and the unchanged 62 KiB
budget. Load the already-collapsed dashboard summary/chart on first opening,
retain its state on reopening, and isolate asset failures with an EN/ES notice
while crossing reports, filters and navigation stay usable.
- Make unused local dropdown wrappers removable through a pure ref/name factory;
preserve every export and the rendered menu's refs, styles and actions.
- Entry is 63,169 bytes / 61.6885 KiB gzip (319 bytes below budget), versus
68,623 bytes before. All initially required JS totals 280,504 versus 285,958
gzip bytes: a real 5,454-byte reduction, with no build/config/budget changes.
First summary opening requests one 5,861-byte gzip chunk. In cold headless
samples at 150ms latency/200KiB/s, first opening took 0.30–1.34s versus
0.02–0.05s before. Loading is announced; current reports stay interactive.
This is an explicit on-request cost for formerly hidden work, not a speed claim.
- Fresh build, 130 unit tests and full npm test pass, including 402 route
navigations and new EN/ES desktop/mobile delayed/failed-asset recovery,
summary keyboard/filter/state and menu keyboard/focus/action checks.
Audit remains six moderate build-chain entries, zero high/critical.
- Publication remains conditional on remote CI; no deployment is claimed here.

## 2026-10-22 — Router security candidate (local, not published)

- Verify the two Router advisories are fixed in react-router 7.18.0+, not in
the unrelated postcss-selector-parser 6.1.5 backport. Prepare Router DOM and
Router 6.30.6 → 7.18.4 with only their required runtime lock entries changed.
- Candidate raw audit drops from eight to six moderate entries; the two Router
entries disappear. Build, 130 unit tests and 402 diagnostic route checks pass,
including mixed-separator rejection and EN/ES desktop/mobile navigation.
- Full npm test **fails** the unchanged 62 KiB entry gate: candidate 67.0146 KiB
versus baseline 60.6943 KiB. No app code, build configuration, audit exception
or budget changed. No candidate push, PR, CI or deployment was performed.
Keep it for review; production remains the verified historical-pattern release.

## 2026-10-22 — Historical pattern confidence (published)

- PR #139 merged at `9893047411d8545df8298eb196a8f585258b1598` after both
Expand Down
12 changes: 12 additions & 0 deletions DECISIONS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# DECISIONS

## 2026-10-22 · A patched dependency candidate must also pass the performance gate

The first Router 7.18.4 candidate cleared both runtime audit entries but
exceeded the existing entry budget. A bounded follow-up loads the existing
closed summary/chart on request and removes unused local wrapper construction,
with explicit loading/failure handling and EN/ES keyboard/recovery regressions.
The full local release suite now passes under the unchanged budget. Release
still requires green remote CI and served-app verification. Do not raise the
budget, move bytes to another eagerly required chunk to hide them, or change
unrelated build packages merely to reduce the advisory count. First summary
opening has a measured cold-network cost; reports remain usable throughout.

## 2026-10-22 · Historical weekday medians are not live observations

The anomaly feed's lowest_today scans 30-day weekday buckets, and sunday_spike
Expand Down
7 changes: 5 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,11 @@ cross-border experience; it is a product hypothesis, not a claim of demand.
- [ ] Verify fresh public history/FX after the repair and observe two subsequent
scheduled publications. Keep first-week usage/cost review pending separately;
no second monitoring automation or manual run counts as a scheduled success.
- [ ] Triage the eight remaining moderate audit package entries without absorbing
unrelated dependency majors or adding broad advisory exceptions.
- [~] Router runtime repair evaluated October 22: local 7.18.4 candidate removes
its two audit entries and passes functional QA, but exceeds the unchanged
initial-JS gate (67.01 vs 62 KiB). Not published. Reduce initial bytes without
weakening the gate before remote CI/publication. Six build-chain entries stay
separate; parser 6.1.5 is not a Router fix. See the existing refresh runbook.
- [x] Current-waits views refresh while open and on tab return/reconnection,
including comparison, crossing, best-time, walk-or-drive and embed routes.
Slow optional feeds no longer delay waits, and the service worker does not
Expand Down
91 changes: 91 additions & 0 deletions docs/REFRESH-OPERATIONS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,96 @@
# Public data refresh

## Router follow-up — 2026-10-22 UTC (local release checks passed)

The earlier candidate checkpoint below records the original failed gate. The
same isolated branch now passes the complete local suite without changing
Vite configuration, the bundle/audit scripts, exceptions or any security setting.
Dependency-only commit `9c2d30d7` remains separate from navigation regressions
and this performance follow-up. Version 6.1.5 is the CSS parser, not Router.

- Profile the exact same installed graph before/after. Direct Router imports,
production deep-entry aliases and pure call annotations alone did not solve
the gate; none of those experiments changed the app/config. Do not patch
upstream Router code or strip its navigation validation.
- The native dashboard disclosure remains closed by default. Its existing
summary/map now loads once on first opening, retains mounted state across
close/reopen, and follows current filters/data. An asset failure produces a
localized status and leaves the report list and route navigation operational;
reloading after network recovery restores the section. No data/feed/threshold
or permissions change. Unused dropdown wrappers retain their API and names,
but their construction can be tree-shaken as a pure factory.
- Exact entry gzip: **63,169 bytes / 61.68848 KiB**, below the unchanged 62 KiB
cap by 319 bytes. The original candidate was 68,623 bytes. Counting **all four
initially required JS chunks**, before is 285,958 and after 280,504 bytes:
**5,454 bytes actually removed from initial loading**. First opening adds one
5,861-byte gzip summary chunk; no new vendor waterfall. Across all routes JS
totals 427,793 versus 427,367 gzip bytes (+426 bytes of splitting/handling).
Neither total nor navigation cost is concealed by the entry-only gate.
- Cold headless EN/ES desktop/mobile samples with simulated 150ms latency,
200KiB/s download and 80KiB/s upload: usable reports 2.00–2.05s after versus
2.02–2.11s before; first chart opening 0.30–1.34s versus 0.02–0.05s. Small
samples are diagnostic, not a production latency/usage/conversion claim.
Loading is visible/announced and list interaction works even while the asset
is deliberately held. This request cost is confined to formerly hidden work.
- Fresh build and **full npm test PASS**, with 130 standalone unit tests and
402 existing navigations. New tests cover both languages and both viewports:
no chart work/request before opening, cold held asset, list filtering while
loading, map keyboard selection, close/reopen identity and cache reuse,
changed filters, menu lane toggle/route actions/Escape focus, asset failure
without ErrorBoundary and successful reload recovery. Existing snapshot aging,
history, sharing/feedback, browser resilience, SEO and alias checks pass.
- Publication: await remote CI on the exact reviewed head, check concurrent
changes again, then use the existing single production workflow after merge.
No second deployment dispatch or new tool/monitor. Preserve newer collector
inputs. Rollback through a normal inverse/revert PR of this scoped code and
dependency diff, keeping collector data; do not roll the whole data bundle back.

## Router candidate review — 2026-10-22 UTC (not published)

- Exact targets: **react-router-dom 6.30.6 → 7.18.4**, resolving **react-router
7.18.4**. Both advisories name react-router, not the CSS selector parser.
[GHSA-wrjc-x8rr-h8h6](https://github.com/remix-run/react-router/security/advisories/GHSA-wrjc-x8rr-h8h6)
affects >=6.0.0,<7.18.0; [GHSA-337j-9hxr-rhxg](https://github.com/remix-run/react-router/security/advisories/GHSA-337j-9hxr-rhxg)
affects >=6.4.0,<7.18.0. Both list fixes at 7.18.0+. Official npm's latest
stable 6.x is 6.30.6; parser 6.1.5 does not mitigate either Router advisory.
- [Versioned official upgrade guide](https://reactrouter.com/7.18.4/upgrading/v6)
requires Node20+/React18+/ReactDOM18+. Current React/DOM 18.3.1, local Node25,
verification Node22 and publisher Node24 satisfy those baselines. The guide's
no-breaking statement is conditional on future flags, not a blanket promise.
This app has only single-segment '*' fallbacks, absolute internal links,
module-level lazy declarations and declarative BrowserRouter; unused data
router/fetcher/hydration changes were not introduced. No app API/import,
React/Vite, security-setting or future-flag change was needed for the candidate.
- Minimal dependency diff: root Router DOM range, the two Router entries,
removal of their unused @remix-run/router, and required cookie/set-cookie-parser.
Six unrelated optional WASI lock additions from npm were excluded. Other
resolved packages are identical. No override or new audit exception.
- Raw candidate audit: **six moderate, zero high/critical**, with both Router
entries absent. Four new library regressions check normalized separators,
external-navigation rejection, internal query/hash/replace/Back/Forward and
encoded separators inside internal parameters. Before/after library behavior
was captured; these tests do not imply the old public app exposed raw URLs.
- Build and 130 unit tests pass. Full npm test **fails at test:bundle**:
68,623 bytes / **67.01465 KiB** initial JS against 62 KiB. Baseline is 62,151
bytes / 60.69434 KiB: **+6,472 bytes**. CSS remains 19.08 KiB under 20 KiB.
The budget and audit scripts are unchanged. No successful full-suite claim.
- Standalone route diagnostics subsequently passed **402 navigations**, existing
freshness/history/share/feedback/language regressions, and added EN/ES
desktop/mobile nested navigation, unknown/encoded-path fallback and checks
against external main-frame navigation. These diagnostic results do not
bypass the failed release gate or authorize publication. Visual headless QA
passed in both languages and widths. SSR/hydration exploit execution was not
tested because the app does not use that mode; package mitigation is supported
by maintainer ranges and the raw audit, not a complete security certification.
- Candidate stays local, with dependency-only and regression/documentation
commits separated. No remote candidate branch, CI, PR or deployment. Live
production remains 98930474 from PR #139. Rollback is local-only: revert the
candidate's support commit then dependency commit in its isolated branch;
preserve other worktrees and collector inputs. No production rollback needed.
- Next: reduce actual initial bytes without raising/evading the gate, rerun
complete checks, then obtain passing remote CI and verify production under
the existing authorization. Do not mix in the separate parser/build-chain work.

## Historical pattern release — 2026-10-22 UTC

- [PR #139](https://github.com/sbc1-code/borderpulse/pull/139) merged reviewed
Expand Down
64 changes: 40 additions & 24 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"news:classify": "node scripts/build-curation-queue.mjs",
"test:bundle": "node scripts/check-bundle-size.mjs",
"test:audit": "node scripts/check-audit.mjs",
"test:trust": "node --test scripts/test-trust-state.mjs scripts/test-local-comparison.mjs scripts/test-browser-state.mjs scripts/test-historical-pattern.mjs",
"test:trust": "node --test scripts/test-trust-state.mjs scripts/test-local-comparison.mjs scripts/test-browser-state.mjs scripts/test-historical-pattern.mjs scripts/test-router-navigation.mjs",
"test:mdx": "node --test scripts/test-mdx-frontmatter.mjs",
"test:writer": "node --test scripts/test-generated-writer.mjs",
"test:refresh": "node --test scripts/test-data-refresh.mjs"
Expand Down Expand Up @@ -86,7 +86,7 @@
"react-dom": "^18.2.0",
"react-hook-form": "^7.75.0",
"react-resizable-panels": "^2.1.7",
"react-router-dom": "^6.26.0",
"react-router-dom": "^7.18.4",
"recharts": "^2.15.4",
"sonner": "^2.0.1",
"tailwind-merge": "^3.6.0",
Expand Down
Loading
Loading