From 079b261757f31c4f0254ffd455083cefd4793852 Mon Sep 17 00:00:00 2001 From: Lakshman Turlapati Date: Thu, 17 Sep 2026 19:20:31 -0500 Subject: [PATCH] feat(showcase): persist anonymous users-by-location and fix IPv6 geo Keep a k-anonymized 365-day last-known region on daily rollups so the stats globe survives the 7-day event wipe, resolve client IPs via Fly-Client-IP with a sibling IPv6 DB-IP table, and stop Chrome from painting the footer language select white-on-white. Co-authored-by: Cursor --- .gitignore | 1 + fly.toml | 8 +- package.json | 2 +- .../src/app/core/stats/fsb-telemetry.types.ts | 6 + .../language-picker.component.scss | 5 +- .../app/pages/stats/stats-page.component.ts | 15 +- showcase/angular/src/styles.scss | 6 +- showcase/server/data/README.md | 65 ++- .../data/dbip-city-lite.ipv6.fixture.csv | 12 + .../server/scripts/refresh-dbip-dataset.mjs | 173 ++++++-- showcase/server/src/db/queries.js | 48 +- showcase/server/src/db/schema.js | 24 +- .../src/middleware/telemetry-rate-limit.js | 19 +- showcase/server/src/routes/public-stats.js | 11 + showcase/server/src/routes/telemetry.js | 60 ++- showcase/server/src/telemetry/housekeeper.js | 42 +- showcase/server/src/utils/client-ip.js | 31 ++ showcase/server/src/utils/ip-geo.js | 409 ++++++++++++++++-- tests/server-client-ip-geo.test.js | 161 +++++++ tests/server-ip-geo-merge.test.js | 20 +- tests/server-ip-geo.test.js | 56 ++- tests/server-no-ip-leak.test.js | 67 +-- tests/server-public-stats-headline.test.js | 3 +- tests/server-region-aggregation.test.js | 73 +++- tests/server-telemetry-housekeeper.test.js | 12 +- tests/showcase-angular-foundation.test.js | 14 + tests/stats-chart-overhaul.test.js | 8 +- 27 files changed, 1170 insertions(+), 181 deletions(-) create mode 100644 showcase/server/data/dbip-city-lite.ipv6.fixture.csv create mode 100644 showcase/server/src/utils/client-ip.js create mode 100644 tests/server-client-ip-geo.test.js diff --git a/.gitignore b/.gitignore index 9b0d3fa8b..4dc4fd145 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ Research/ # NEVER committed. The tiny committed test fixture (*.fixture.csv) is kept. showcase/server/data/dbip-city-lite.* !showcase/server/data/dbip-city-lite.fixture.csv +!showcase/server/data/dbip-city-lite.ipv6.fixture.csv .claude/worktrees/ BUG-REPORT-*.md dist/skill/ diff --git a/fly.toml b/fly.toml index 22ea25277..a22ce1410 100644 --- a/fly.toml +++ b/fly.toml @@ -10,10 +10,12 @@ primary_region = 'sjc' NODE_ENV = 'production' # Worldwide IP->region dataset (DB-IP IP-to-City Lite, generated by # showcase/server/scripts/refresh-dbip-dataset.mjs). Lives on the mounted - # /data volume (NOT baked into the image). Safe to set before the file exists: - # ip-geo.js degrades to 'unknown' until it is uploaded, then restart the - # machine so the lazy loader re-reads. See showcase/server/data/README.md. + # /data volume (NOT baked into the image). Safe to set before the files exist: + # ip-geo.js degrades to 'unknown' until they are uploaded, then restart the + # machine so the lazy loader re-reads. IPv4 + sibling IPv6. See + # showcase/server/data/README.md. DBIP_DATASET_PATH = '/data/dbip-city-lite.csv' + DBIP_IPV6_DATASET_PATH = '/data/dbip-city-lite.ipv6.csv' [http_service] internal_port = 3847 diff --git a/package.json b/package.json index 64015a9b7..b1b139c7c 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "version:check": "node scripts/sync-product-version.mjs --check", "build": "node esbuild.config.js", "build:cfworker": "node_modules/.bin/esbuild node_modules/@cfworker/json-schema/dist/esm/index.js --bundle --format=iife --global-name=CfworkerJsonSchema --platform=browser --target=chrome120 --legal-comments=none --outfile=extension/lib/cfworker-json-schema.min.js", - "test": "node tests/test-overlay-state.js && node tests/cost-tracker-ordering.test.js && node tests/runtime-contracts.test.js && node tests/ai-integration-analytics.test.js && node tests/dashboard-runtime-state.test.js && node tests/task-router.test.js && node tests/agent-provider-forbidden-flags.test.js && node tests/phase60-full-tests-harness.test.js && node tests/phase64-full-tests-harness.test.js && node tests/phase65-full-tests-harness.test.js && node tests/delegation-routing.test.js && node tests/delegation-consent.test.js && npm --prefix mcp run build && node tests/delegation-event-store.test.js && node tests/delegation-controller.test.js && node tests/delegation-sidepanel-ui.test.js && node tests/delegation-phase-contract.test.js && node tests/mcp-native-host-packaging.test.js --section workflow-and-pack && node tests/mcp-native-host-protocol.test.js && node tests/mcp-native-host-daemon.test.js && node tests/mcp-native-host-registry-helper.test.js && node tests/mcp-native-host-install.test.js && node tests/native-host-background-wake.test.js && node tests/mcp-bridge-client-lifecycle.test.js && node tests/mcp-bridge-topology.test.js && node tests/mcp-reverse-channel-contract.test.js && node tests/mcp-bridge-auth.test.js && node tests/mcp-bridge-background-dispatch.test.js && node tests/agent-protocol-drift-diagnostics.test.js && node tests/mcp-tool-routing-contract.test.js && node tests/mcp-visual-session-contract.test.js && node tests/mcp-restricted-tab.test.js && node tests/mcp-recovery-messaging.test.js && node tests/mcp-in-flight-session-lookup.test.js && node tests/mcp-version-parity.test.js && node tests/mcp-agent-provider-contract.test.js && node tests/mcp-adapter-compatibility.test.js && node tests/mcp-agent-connection-test.test.js && node tests/mcp-claude-code-adapter.test.js && node tests/mcp-agent-drift-smoke.test.js && node tests/mcp-agent-stream-fixture.test.js && node tests/mcp-spawn-supervisor.test.js && node tests/mcp-agent-orphan-recovery.test.js && node tests/mcp-diagnostics-status.test.js && node tests/mcp-install-platforms.test.js && node tests/mcp-setup-guidance.test.js && node tests/mcp-client-identity.test.js && node tests/mcp-client-inventory.test.js && node tests/mcp-agent-providers-storage.test.js && node tests/onboarding-agent-provider-clicks.test.js && node tests/mcp-client-merged-view.test.js && node tests/mcp-client-identity-integration.test.js && node tests/providers-panel-logic.test.js && node tests/providers-panel-ui.test.js && node tests/turn-result.test.js && node tests/action-history.test.js && node tests/universal-provider-lmstudio.test.js && node tests/lmstudio-agent-request.test.js && node tests/lmstudio-startup-preflight.test.js && node tests/lmstudio-settings-persistence.test.js && node tests/onboarding-lmstudio.test.js && node tests/config-lmstudio.test.js && node tests/cost-tracker.test.js && node tests/install-identity.test.js && node tests/mcp-pricing.test.js && node tests/mcp-pricing-data-parity.test.js && node tests/mcp-metrics-recorder.test.js && node tests/mcp-dispatcher-client-label.test.js && node tests/mcp-session-recorder.test.js && node tests/automation-logger-mcp-retention.test.js && node tests/mcp-session-settings-ui.test.js && node tests/knowledge-graph-dedup.test.js && node tests/mcp-metrics-no-pii-leak.test.js && node tests/telemetry-collector.test.js && node tests/telemetry-collector-strips-internal-fields.test.js && node tests/telemetry-payload-allowlist.test.js && node tests/telemetry-registry-bootstrap.test.js && node tests/extension-record-dispatch-serializes.test.js && node tests/server-trust-proxy.test.js && node tests/server-telemetry-salt-rotation.test.js && node tests/server-telemetry-rate-limit.test.js && node tests/server-telemetry-body-cap.test.js && node tests/server-telemetry-parser-rate-limit.test.js && node tests/server-telemetry-batch-cap.test.js && node tests/server-telemetry-allowlist.test.js && node tests/server-telemetry-event-id-dedup.test.js && node tests/server-telemetry-timestamp-tolerance.test.js && node tests/server-telemetry-daily-budget.test.js && node tests/server-telemetry-ip-daily-budget.test.js && node tests/server-telemetry-sec-gpc.test.js && node tests/server-telemetry-optout-forget.test.js && node tests/telemetry-active-tracker-bounds.test.js && node tests/telemetry-uuid-budget-memory.test.js && node tests/server-telemetry-housekeeper.test.js && node tests/server-public-stats-headline.test.js && node tests/server-public-stats-series.test.js && node tests/server-public-stats-cache.test.js && node tests/server-public-stats-no-auth.test.js && node tests/server-github-cache.test.js && node tests/server-github-poller.test.js && node tests/fsb-telemetry-service.test.js && node tests/stats-view-state.test.js && node tests/showcase-build-smoke.test.js && node tests/showcase-route-fallback.test.js && node tests/stats-chart-overhaul.test.js && node scripts/verify-store-listing.mjs && node tests/verify-store-listing.test.js && node tests/cumulative-commits-aggregator.test.js && node tests/dashboard-stream-readiness-ping.test.js && node tests/dashboard-stream-pending-intent.test.js && node tests/dashboard-stream-recovery-parity.test.js && node tests/server-ws-backpressure.test.js && node tests/server-ws-phantomstream-relay-compat.test.js && node tests/showcase-privacy-page.test.js && node tests/server-no-ip-leak.test.js && node tests/server-ip-geo.test.js && node tests/server-ip-geo-merge.test.js && node tests/server-ip-geo-scale.test.js && node tests/server-region-aggregation.test.js && node tests/transcript-store.test.js && node tests/hook-pipeline.test.js && node tests/session-schema.test.js && node tests/state-emitter.test.js && node tests/secure-config-credential-vault.test.js && node tests/qr-pairing.test.js && node tests/ws-client-decompress.test.js && node tests/dashboard-task-direct-start.test.js && node tests/phantom-stream-protocol-envelope.test.js && node tests/phantom-stream-differential-parity.test.js && node tests/phantom-stream-remote-control-parity.test.js && node tests/phantom-stream-public-package.test.js && node tests/phantom-stream-exports.test.js && node tests/phantom-stream-content-bundle.test.js && node tests/phantom-stream-capture-adapter.test.js && node tests/phantom-stream-sidechannels.test.js && node tests/phantom-stream-security-masking.test.js && node tests/phantom-stream-dashboard-viewer-bundle.test.js && node tests/phantom-stream-static-viewer.test.js && node tests/phantom-stream-dashboard-parity.test.js && node tests/phantom-stream-dashboard-sidechannels.test.js && node tests/phantom-stream-media-sync.test.js && node tests/phantom-stream-media-wiring.test.js && node tests/dom-stream-perf.test.js && node tests/extension-content-script-files-completeness.test.js && node tests/dom-analysis-viewport-priority.test.js && node tests/redact-for-log.test.js && node tests/diagnostics-ring-buffer.test.js && node tests/agent-sunset-back-end.test.js && node tests/agent-sunset-control-panel.test.js && node tests/agent-sunset-showcase.test.js && node tests/sync-tab-runtime.test.js && node tests/remote-control-rebrand.test.js && node tests/server-accept-language.test.js && node tests/server-legacy-html-redirects.test.js && node tests/metrics-wireup.test.js && node tests/dashboard-metrics-render.test.js && node tests/stuck-action-repetition.test.js && node tests/goal-progress-tracker.test.js && node tests/model-discovery.test.js && node tests/model-discovery-ui.test.js && node tests/model-combobox-ui.test.js && node tests/settings-card-select-clipping.test.js && node tests/control-panel-scroll-containment.test.js && node tests/model-discovery-runtime.test.js && node tests/overlay-stability-cadence.test.js && node tests/overlay-content-audit.test.js && node tests/action-icon-behavior.test.js && node tests/meta-cognitive-tracker.test.js && node tests/agent-cap-recommendation.test.js && node tests/agent-cap-storage.test.js && node tests/agent-cap-ui.test.js && node tests/agent-registry.test.js && node tests/selected-tab-state.test.js && node tests/change-report-builder.test.js && node tests/change-report-size-cap.test.js && node tests/change-report-cross-origin.test.js && node tests/change-report-dispatcher.test.js && node tests/change-report-read-tools-excluded.test.js && node tests/change-report-toggle.test.js && node tests/change-report-settings-ui.test.js && node tests/agent-tab-resolver.test.js && node tests/read-tool-tab-resolution.test.js && node tests/open-tab-background-default.test.js && node tests/visual-session-agent-scoped.test.js && node tests/action-tool-agent-scoped.test.js && node tests/recovery-tools-bootstrap.test.js && node tests/legacy-agent-synthesis.test.js && node tests/visual-session-reentry.test.js && node tests/ownership-error-codes.test.js && node tests/multi-agent-regression.test.js && node tests/tool-definitions-parity.test.js && node tests/mcp-numeric-param-coercion.test.js && node tests/visual-session-schema-lock.test.js && node tests/mcp-visual-tick-lifecycle.test.js && node tests/agent-id-threading.test.js && node tests/skill-fsb-spec.test.js && node tests/agent-loop-empty-contents.test.js && node --test tests/google-sheets-session.test.js tests/google-sheets-content-actions.test.js tests/gsheets-handler.test.js tests/google-sheets-wiring.test.js tests/spreadsheet-record-redaction.test.js && node tests/lattice-public-package.test.js && node tests/lattice-smoke.test.js && node tests/lattice-tripwire-smoke.test.js && node tests/lattice-checkpoint-smoke.test.js && node tests/lattice-providers-smoke.test.js && node tests/lattice-survivability-smoke.test.js && node tests/lattice-provider-bridge-smoke.test.js && node tests/lattice-host-step-transition-smoke.test.js && node tests/lattice-session-replay.test.js && node tests/lattice-replay-background-contract.test.js && node tests/lattice-step-emitter-smoke.test.js && node tests/mcp-philosophy-parity-smoke.test.js && node tests/sidepanel-tab-aware-smoke.test.js && node tests/sidepanel-message-log-smoke.test.js && node tests/sidepanel-mcpvisualsession-listener.test.js && node tests/delegation-sidepanel-tab-follow.test.js && node tests/sidepanel-tab-scoping-fix-redo-smoke.test.js && node tests/sidepanel-progress-tick-setter-routing.test.js && node tests/sidepanel-background-tab-completion.test.js && node tests/sidepanel-multi-document-fanout.test.js && node tests/sidepanel-automation-runner.test.js && node tests/trigger-store.test.js && node tests/trigger-lifecycle.test.js && node tests/value-extractor.test.js && node tests/trigger-manager.test.js && node tests/trigger-cap.test.js && node tests/trigger-observe.test.js && node tests/trigger-observe-pulse.test.js && node tests/trigger-refresh-poll.test.js && node tests/trigger-tool-dispatcher.test.js && node tests/trigger-blocking-reporting.test.js && node tests/capability-recipe-schema.test.js && node tests/capability-interpreter.test.js && node tests/recipe-path-guard.test.js && node tests/capability-fetch.test.js && node tests/capability-search-eval.test.js && node tests/capability-mcp-surface.test.js && node tests/capability-router.test.js && node tests/capability-autopilot-parity.test.js && node tests/capability-head-handlers.test.js && node tests/consent-policy-store.test.js && node tests/consent-gate.test.js && node tests/consent-mutation-gate.test.js && node tests/consent-chokepoint.test.js && node tests/audit-log.test.js && node tests/audit-log-no-secret.test.js && node tests/recipe-signature.test.js && node tests/recipe-signature-interpreter-hook.test.js && node tests/service-denylist.test.js && node tests/classification-gate.test.js && node tests/provenance-scaffold.test.js && node tests/upload-file-route.test.js && node tests/upload-path-denylist.test.js && node tests/consent-audit-settings-ui.test.js && node tests/agent-loop-iterator-guard.test.js && node tests/network-capture.test.js && node tests/network-capture-consent.test.js && node tests/network-capture-redaction.test.js && node tests/recipe-synthesizer.test.js && node tests/learned-recipe-store.test.js && node tests/learned-search-add.test.js && node tests/learned-t2-outranking.test.js && node tests/learned-promote-after-replay.test.js && node tests/discovery-seeds-load.test.js && node tests/seed-resolve-t2.test.js && node tests/recipe-learn-pending-affordance.test.js && node tests/learned-local-provenance-exempt.test.js && node tests/provider-parity.test.js && node tests/recipe-schema-lock.test.js && node tests/capability-rot-detector.test.js && node tests/relearn-coalescing.test.js && node tests/rot-recurrence-classify.test.js && node tests/app-degraded-surfacing.test.js && node tests/relearn-router-wiring.test.js && node tests/import-extraction.test.js && node tests/import-forbidden-prescan.test.js && node tests/import-classify-gate-call.test.js && node tests/catalog-crosscheck.test.js && node tests/no-dead-entry.test.js && node tests/catalog-inline-shape.test.js && node tests/head-handler-cap.test.js && node tests/head-handler-upgrade.test.js && node tests/confluence-t1-handler.test.js && node tests/verify-origin-classification.test.js && node tests/guarded-write-failclosed.test.js && node tests/breadth-search-return.test.js && node tests/breadth-batch-gate.test.js && node tests/backing-status-annotation.test.js && node tests/t1-port-contract.test.js && node tests/t1-port-contract-gate.test.js && node tests/dom-only-default.test.js && node tests/sensitive-write-import-gate.test.js && node tests/coverage-report.test.js && node tests/payment-op-guard.test.js && node tests/vendor-augment-preserved.test.js && node tests/no-duplicate-stem.test.js && node tests/full-corpus-screen.test.js && node tests/full-corpus-scale.test.js && node tests/keyboard-attach-robustness.test.js && node --import tsx tests/no-orphan-descriptor.test.js", + "test": "node tests/test-overlay-state.js && node tests/cost-tracker-ordering.test.js && node tests/runtime-contracts.test.js && node tests/ai-integration-analytics.test.js && node tests/dashboard-runtime-state.test.js && node tests/task-router.test.js && node tests/agent-provider-forbidden-flags.test.js && node tests/phase60-full-tests-harness.test.js && node tests/phase64-full-tests-harness.test.js && node tests/phase65-full-tests-harness.test.js && node tests/delegation-routing.test.js && node tests/delegation-consent.test.js && npm --prefix mcp run build && node tests/delegation-event-store.test.js && node tests/delegation-controller.test.js && node tests/delegation-sidepanel-ui.test.js && node tests/delegation-phase-contract.test.js && node tests/mcp-native-host-packaging.test.js --section workflow-and-pack && node tests/mcp-native-host-protocol.test.js && node tests/mcp-native-host-daemon.test.js && node tests/mcp-native-host-registry-helper.test.js && node tests/mcp-native-host-install.test.js && node tests/native-host-background-wake.test.js && node tests/mcp-bridge-client-lifecycle.test.js && node tests/mcp-bridge-topology.test.js && node tests/mcp-reverse-channel-contract.test.js && node tests/mcp-bridge-auth.test.js && node tests/mcp-bridge-background-dispatch.test.js && node tests/agent-protocol-drift-diagnostics.test.js && node tests/mcp-tool-routing-contract.test.js && node tests/mcp-visual-session-contract.test.js && node tests/mcp-restricted-tab.test.js && node tests/mcp-recovery-messaging.test.js && node tests/mcp-in-flight-session-lookup.test.js && node tests/mcp-version-parity.test.js && node tests/mcp-agent-provider-contract.test.js && node tests/mcp-adapter-compatibility.test.js && node tests/mcp-agent-connection-test.test.js && node tests/mcp-claude-code-adapter.test.js && node tests/mcp-agent-drift-smoke.test.js && node tests/mcp-agent-stream-fixture.test.js && node tests/mcp-spawn-supervisor.test.js && node tests/mcp-agent-orphan-recovery.test.js && node tests/mcp-diagnostics-status.test.js && node tests/mcp-install-platforms.test.js && node tests/mcp-setup-guidance.test.js && node tests/mcp-client-identity.test.js && node tests/mcp-client-inventory.test.js && node tests/mcp-agent-providers-storage.test.js && node tests/onboarding-agent-provider-clicks.test.js && node tests/mcp-client-merged-view.test.js && node tests/mcp-client-identity-integration.test.js && node tests/providers-panel-logic.test.js && node tests/providers-panel-ui.test.js && node tests/turn-result.test.js && node tests/action-history.test.js && node tests/universal-provider-lmstudio.test.js && node tests/lmstudio-agent-request.test.js && node tests/lmstudio-startup-preflight.test.js && node tests/lmstudio-settings-persistence.test.js && node tests/onboarding-lmstudio.test.js && node tests/config-lmstudio.test.js && node tests/cost-tracker.test.js && node tests/install-identity.test.js && node tests/mcp-pricing.test.js && node tests/mcp-pricing-data-parity.test.js && node tests/mcp-metrics-recorder.test.js && node tests/mcp-dispatcher-client-label.test.js && node tests/mcp-session-recorder.test.js && node tests/automation-logger-mcp-retention.test.js && node tests/mcp-session-settings-ui.test.js && node tests/knowledge-graph-dedup.test.js && node tests/mcp-metrics-no-pii-leak.test.js && node tests/telemetry-collector.test.js && node tests/telemetry-collector-strips-internal-fields.test.js && node tests/telemetry-payload-allowlist.test.js && node tests/telemetry-registry-bootstrap.test.js && node tests/extension-record-dispatch-serializes.test.js && node tests/server-trust-proxy.test.js && node tests/server-telemetry-salt-rotation.test.js && node tests/server-telemetry-rate-limit.test.js && node tests/server-telemetry-body-cap.test.js && node tests/server-telemetry-parser-rate-limit.test.js && node tests/server-telemetry-batch-cap.test.js && node tests/server-telemetry-allowlist.test.js && node tests/server-telemetry-event-id-dedup.test.js && node tests/server-telemetry-timestamp-tolerance.test.js && node tests/server-telemetry-daily-budget.test.js && node tests/server-telemetry-ip-daily-budget.test.js && node tests/server-telemetry-sec-gpc.test.js && node tests/server-telemetry-optout-forget.test.js && node tests/telemetry-active-tracker-bounds.test.js && node tests/telemetry-uuid-budget-memory.test.js && node tests/server-telemetry-housekeeper.test.js && node tests/server-public-stats-headline.test.js && node tests/server-public-stats-series.test.js && node tests/server-public-stats-cache.test.js && node tests/server-public-stats-no-auth.test.js && node tests/server-github-cache.test.js && node tests/server-github-poller.test.js && node tests/fsb-telemetry-service.test.js && node tests/stats-view-state.test.js && node tests/showcase-build-smoke.test.js && node tests/showcase-route-fallback.test.js && node tests/stats-chart-overhaul.test.js && node scripts/verify-store-listing.mjs && node tests/verify-store-listing.test.js && node tests/cumulative-commits-aggregator.test.js && node tests/dashboard-stream-readiness-ping.test.js && node tests/dashboard-stream-pending-intent.test.js && node tests/dashboard-stream-recovery-parity.test.js && node tests/server-ws-backpressure.test.js && node tests/server-ws-phantomstream-relay-compat.test.js && node tests/showcase-privacy-page.test.js && node tests/server-no-ip-leak.test.js && node tests/server-ip-geo.test.js && node tests/server-client-ip-geo.test.js && node tests/server-ip-geo-merge.test.js && node tests/server-ip-geo-scale.test.js && node tests/server-region-aggregation.test.js && node tests/transcript-store.test.js && node tests/hook-pipeline.test.js && node tests/session-schema.test.js && node tests/state-emitter.test.js && node tests/secure-config-credential-vault.test.js && node tests/qr-pairing.test.js && node tests/ws-client-decompress.test.js && node tests/dashboard-task-direct-start.test.js && node tests/phantom-stream-protocol-envelope.test.js && node tests/phantom-stream-differential-parity.test.js && node tests/phantom-stream-remote-control-parity.test.js && node tests/phantom-stream-public-package.test.js && node tests/phantom-stream-exports.test.js && node tests/phantom-stream-content-bundle.test.js && node tests/phantom-stream-capture-adapter.test.js && node tests/phantom-stream-sidechannels.test.js && node tests/phantom-stream-security-masking.test.js && node tests/phantom-stream-dashboard-viewer-bundle.test.js && node tests/phantom-stream-static-viewer.test.js && node tests/phantom-stream-dashboard-parity.test.js && node tests/phantom-stream-dashboard-sidechannels.test.js && node tests/phantom-stream-media-sync.test.js && node tests/phantom-stream-media-wiring.test.js && node tests/dom-stream-perf.test.js && node tests/extension-content-script-files-completeness.test.js && node tests/dom-analysis-viewport-priority.test.js && node tests/redact-for-log.test.js && node tests/diagnostics-ring-buffer.test.js && node tests/agent-sunset-back-end.test.js && node tests/agent-sunset-control-panel.test.js && node tests/agent-sunset-showcase.test.js && node tests/sync-tab-runtime.test.js && node tests/remote-control-rebrand.test.js && node tests/server-accept-language.test.js && node tests/server-legacy-html-redirects.test.js && node tests/metrics-wireup.test.js && node tests/dashboard-metrics-render.test.js && node tests/stuck-action-repetition.test.js && node tests/goal-progress-tracker.test.js && node tests/model-discovery.test.js && node tests/model-discovery-ui.test.js && node tests/model-combobox-ui.test.js && node tests/settings-card-select-clipping.test.js && node tests/control-panel-scroll-containment.test.js && node tests/model-discovery-runtime.test.js && node tests/overlay-stability-cadence.test.js && node tests/overlay-content-audit.test.js && node tests/action-icon-behavior.test.js && node tests/meta-cognitive-tracker.test.js && node tests/agent-cap-recommendation.test.js && node tests/agent-cap-storage.test.js && node tests/agent-cap-ui.test.js && node tests/agent-registry.test.js && node tests/selected-tab-state.test.js && node tests/change-report-builder.test.js && node tests/change-report-size-cap.test.js && node tests/change-report-cross-origin.test.js && node tests/change-report-dispatcher.test.js && node tests/change-report-read-tools-excluded.test.js && node tests/change-report-toggle.test.js && node tests/change-report-settings-ui.test.js && node tests/agent-tab-resolver.test.js && node tests/read-tool-tab-resolution.test.js && node tests/open-tab-background-default.test.js && node tests/visual-session-agent-scoped.test.js && node tests/action-tool-agent-scoped.test.js && node tests/recovery-tools-bootstrap.test.js && node tests/legacy-agent-synthesis.test.js && node tests/visual-session-reentry.test.js && node tests/ownership-error-codes.test.js && node tests/multi-agent-regression.test.js && node tests/tool-definitions-parity.test.js && node tests/mcp-numeric-param-coercion.test.js && node tests/visual-session-schema-lock.test.js && node tests/mcp-visual-tick-lifecycle.test.js && node tests/agent-id-threading.test.js && node tests/skill-fsb-spec.test.js && node tests/agent-loop-empty-contents.test.js && node --test tests/google-sheets-session.test.js tests/google-sheets-content-actions.test.js tests/gsheets-handler.test.js tests/google-sheets-wiring.test.js tests/spreadsheet-record-redaction.test.js && node tests/lattice-public-package.test.js && node tests/lattice-smoke.test.js && node tests/lattice-tripwire-smoke.test.js && node tests/lattice-checkpoint-smoke.test.js && node tests/lattice-providers-smoke.test.js && node tests/lattice-survivability-smoke.test.js && node tests/lattice-provider-bridge-smoke.test.js && node tests/lattice-host-step-transition-smoke.test.js && node tests/lattice-session-replay.test.js && node tests/lattice-replay-background-contract.test.js && node tests/lattice-step-emitter-smoke.test.js && node tests/mcp-philosophy-parity-smoke.test.js && node tests/sidepanel-tab-aware-smoke.test.js && node tests/sidepanel-message-log-smoke.test.js && node tests/sidepanel-mcpvisualsession-listener.test.js && node tests/delegation-sidepanel-tab-follow.test.js && node tests/sidepanel-tab-scoping-fix-redo-smoke.test.js && node tests/sidepanel-progress-tick-setter-routing.test.js && node tests/sidepanel-background-tab-completion.test.js && node tests/sidepanel-multi-document-fanout.test.js && node tests/sidepanel-automation-runner.test.js && node tests/trigger-store.test.js && node tests/trigger-lifecycle.test.js && node tests/value-extractor.test.js && node tests/trigger-manager.test.js && node tests/trigger-cap.test.js && node tests/trigger-observe.test.js && node tests/trigger-observe-pulse.test.js && node tests/trigger-refresh-poll.test.js && node tests/trigger-tool-dispatcher.test.js && node tests/trigger-blocking-reporting.test.js && node tests/capability-recipe-schema.test.js && node tests/capability-interpreter.test.js && node tests/recipe-path-guard.test.js && node tests/capability-fetch.test.js && node tests/capability-search-eval.test.js && node tests/capability-mcp-surface.test.js && node tests/capability-router.test.js && node tests/capability-autopilot-parity.test.js && node tests/capability-head-handlers.test.js && node tests/consent-policy-store.test.js && node tests/consent-gate.test.js && node tests/consent-mutation-gate.test.js && node tests/consent-chokepoint.test.js && node tests/audit-log.test.js && node tests/audit-log-no-secret.test.js && node tests/recipe-signature.test.js && node tests/recipe-signature-interpreter-hook.test.js && node tests/service-denylist.test.js && node tests/classification-gate.test.js && node tests/provenance-scaffold.test.js && node tests/upload-file-route.test.js && node tests/upload-path-denylist.test.js && node tests/consent-audit-settings-ui.test.js && node tests/agent-loop-iterator-guard.test.js && node tests/network-capture.test.js && node tests/network-capture-consent.test.js && node tests/network-capture-redaction.test.js && node tests/recipe-synthesizer.test.js && node tests/learned-recipe-store.test.js && node tests/learned-search-add.test.js && node tests/learned-t2-outranking.test.js && node tests/learned-promote-after-replay.test.js && node tests/discovery-seeds-load.test.js && node tests/seed-resolve-t2.test.js && node tests/recipe-learn-pending-affordance.test.js && node tests/learned-local-provenance-exempt.test.js && node tests/provider-parity.test.js && node tests/recipe-schema-lock.test.js && node tests/capability-rot-detector.test.js && node tests/relearn-coalescing.test.js && node tests/rot-recurrence-classify.test.js && node tests/app-degraded-surfacing.test.js && node tests/relearn-router-wiring.test.js && node tests/import-extraction.test.js && node tests/import-forbidden-prescan.test.js && node tests/import-classify-gate-call.test.js && node tests/catalog-crosscheck.test.js && node tests/no-dead-entry.test.js && node tests/catalog-inline-shape.test.js && node tests/head-handler-cap.test.js && node tests/head-handler-upgrade.test.js && node tests/confluence-t1-handler.test.js && node tests/verify-origin-classification.test.js && node tests/guarded-write-failclosed.test.js && node tests/breadth-search-return.test.js && node tests/breadth-batch-gate.test.js && node tests/backing-status-annotation.test.js && node tests/t1-port-contract.test.js && node tests/t1-port-contract-gate.test.js && node tests/dom-only-default.test.js && node tests/sensitive-write-import-gate.test.js && node tests/coverage-report.test.js && node tests/payment-op-guard.test.js && node tests/vendor-augment-preserved.test.js && node tests/no-duplicate-stem.test.js && node tests/full-corpus-screen.test.js && node tests/full-corpus-scale.test.js && node tests/keyboard-attach-robustness.test.js && node --import tsx tests/no-orphan-descriptor.test.js", "test:openai-request": "node tests/openai-agent-request.test.js", "test:grok-build": "npm --prefix mcp run build && node tests/mcp-grok-build-adapter.test.js", "test:lattice": "node tests/lattice-public-package.test.js && node tests/lattice-smoke.test.js && node tests/lattice-tripwire-smoke.test.js && node tests/lattice-checkpoint-smoke.test.js && node tests/lattice-providers-smoke.test.js && node tests/lattice-survivability-smoke.test.js && node tests/lattice-provider-bridge-smoke.test.js && node tests/lattice-host-step-transition-smoke.test.js && node tests/lattice-session-replay.test.js && node --test tests/lattice-replay-playback.test.js && node tests/lattice-replay-background-contract.test.js && node tests/lattice-step-emitter-smoke.test.js", diff --git a/showcase/angular/src/app/core/stats/fsb-telemetry.types.ts b/showcase/angular/src/app/core/stats/fsb-telemetry.types.ts index a90681f95..defdc73d1 100644 --- a/showcase/angular/src/app/core/stats/fsb-telemetry.types.ts +++ b/showcase/angular/src/app/core/stats/fsb-telemetry.types.ts @@ -63,6 +63,12 @@ export interface FSBTelemetryHeadline { popular_agents: Array<{ label: string; uniq: number }>; /** Latest day's coarse region aggregate with a k>=5 floor. */ popular_regions: Array<{ label: string; uniq: number }>; + /** + * Last-known coarse region per install across the retained 365-day rollups, + * k>=5 floored. Anonymous (country / US-state labels only). Powers the globe + * so location survives the 7-day raw-event wipe. + */ + users_by_region_365d?: Array<{ label: string; uniq: number }>; /** Compatibility alias for avg_agents_per_reporting_user. */ avg_agents_per_user: number; /** active_agents_now / active_agents_reporting_users_now. */ diff --git a/showcase/angular/src/app/layout/language-picker/language-picker.component.scss b/showcase/angular/src/app/layout/language-picker/language-picker.component.scss index b17fcd1f7..fe4712d0f 100644 --- a/showcase/angular/src/app/layout/language-picker/language-picker.component.scss +++ b/showcase/angular/src/app/layout/language-picker/language-picker.component.scss @@ -67,9 +67,12 @@ appearance: none; -webkit-appearance: none; -moz-appearance: none; - background: transparent; + /* Blink ignores a fully transparent select background and keeps UA Field + * (white unless color-scheme is dark). --bg-card is opaque and matches the footer. */ + background-color: var(--bg-card); border: 0; color: inherit; + color-scheme: inherit; font: inherit; padding: 0.25rem 1.25rem 0.25rem 0.5rem; cursor: pointer; diff --git a/showcase/angular/src/app/pages/stats/stats-page.component.ts b/showcase/angular/src/app/pages/stats/stats-page.component.ts index 256cebafd..719ce2958 100644 --- a/showcase/angular/src/app/pages/stats/stats-page.component.ts +++ b/showcase/angular/src/app/pages/stats/stats-page.component.ts @@ -298,7 +298,7 @@ export class StatsPageComponent implements OnInit, OnDestroy { } get accessibleGlobeData(): readonly AccessibleDatum[] { - return (this.latestFsbHeadline?.popular_regions ?? []).map((item) => ({ + return this.globeRegionList.map((item) => ({ label: this.displayLabel(item.label), value: this.fmtNum(item.uniq), })); @@ -415,8 +415,13 @@ export class StatsPageComponent implements OnInit, OnDestroy { // an explicit "still gathering data" message when this is false rather // than silently showing a globe with no nodes. get hasPlottableRegions(): boolean { - const regions = this.latestFsbHeadline?.popular_regions ?? []; - return regions.some((r) => regionCentroid(r.label) !== null); + return this.globeRegionList.some((r) => regionCentroid(r.label) !== null); + } + + private get globeRegionList(): readonly { label: string; uniq: number }[] { + const persistent = this.latestFsbHeadline?.users_by_region_365d; + if (persistent && persistent.length > 0) return persistent; + return this.latestFsbHeadline?.popular_regions ?? []; } get fanItemsLeft(): readonly FanItem[] { @@ -793,7 +798,7 @@ export class StatsPageComponent implements OnInit, OnDestroy { if (this.selectedView === 'fsb-active-now') { const key = JSON.stringify({ - regions: this.latestFsbHeadline?.popular_regions ?? [], + regions: this.globeRegionList, reducedMotion: this.prefersReducedMotion, theme: typeof document === 'undefined' ? '' @@ -888,7 +893,7 @@ export class StatsPageComponent implements OnInit, OnDestroy { // moderate jitter radius since we only have a single centroid per label, // not a real distribution. private buildGlobeRegions(): GlobeRegion[] { - const list = this.latestFsbHeadline?.popular_regions ?? []; + const list = this.globeRegionList; const regions: GlobeRegion[] = []; for (const { label, uniq } of list) { const centroid = regionCentroid(label); diff --git a/showcase/angular/src/styles.scss b/showcase/angular/src/styles.scss index c1ecb4f33..fcd7cf72f 100644 --- a/showcase/angular/src/styles.scss +++ b/showcase/angular/src/styles.scss @@ -1,8 +1,11 @@ @import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css'); @import url('https://unpkg.com/@phosphor-icons/web@2.1.1/src/regular/style.css'); -/* Shared showcase foundation: tokens, reset, typography, and utilities only. */ +/* Shared showcase foundation: tokens, reset, typography, and utilities only. + * color-scheme is required so native form controls (the footer