SlowGuardian V10 — ground-up LTS recode (Scramjet-only, Astro frontend) - #19
Open
zgr2575 wants to merge 40 commits into
Open
SlowGuardian V10 — ground-up LTS recode (Scramjet-only, Astro frontend)#19zgr2575 wants to merge 40 commits into
zgr2575 wants to merge 40 commits into
Conversation
Adds V10_RECODE_PLAN.md — a stability-first, ground-up recode plan derived from a full V9 code audit and research into modern web-unblocker architecture, stealth/cloaking, frontend, and backend/LTS practices. Core decisions proposed: - Collapse 5 proxy engines to one (Scramjet) over a single Wisp transport - One service worker, one auth path; cut Spotify/KeyAuth/AdSense/Replit DB - Astro MPA frontend; Express backend kept; better-sqlite3/memory storage - Real test pyramid incl. Playwright proxy smoke test; LTS branch + release-please - Honest stealth: default tab-cloak + fixed panic key, opt-in about:blank/blob Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Revise the deploy plan to keep Vercel support (per maintainer): static Astro frontend on Vercel, persistent Wisp proxy backend on Render/Railway/ Fly/self-host. Adds section 6.1 documenting the split-deploy topology and why running Wisp as Vercel serverless functions is not viable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
- DESIGN_V10.md: judged design-system spec (NEON DECK arcade-console direction chosen for surviving the Chromebook perf budget; absorbs command palette + film-grain from the runner-up directions). Full token set, theming architecture, component inventory, motion set, performance-mode strategy, and CI-enforced budgets. - docs/design/v10-neon-deck-mockup.html: self-contained clickable mockup — live theme (Arcade/Midnight/Carbon/Paper) + accent switching, catalog search/filter over real titles, command palette, tab-cloak and panic demos. All effects static CSS or compositor-only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Scrap the arcade/neon mockup per maintainer direction. New UI is Apple Liquid Glass, dark-mode-first: translucent frosted material, specular edges, ambient light field, floating panels, one restrained accent. Real backdrop-filter on capable devices with a solid-glass fallback (@supports + data-perf) so old Chromebooks stay smooth. Light Liquid Glass available via toggle. Includes live accent switching, catalog search, and a Cmd-K command palette. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Start the ground-up recode under v10/ (alongside V9 until cutover so main stays shippable). Adds the design-token stylesheet extracted from the approved Liquid Glass direction, and a BUILD_STATUS tracker with the locked decisions and phase checklist. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Replace the flat filter-grid (felt cluttered) with a featured billboard hero + side-scrolling category rows of landscape tiles (title overlaid on the art, scroll-snap, bleeds off the edge). Search collapses rows into a results grid. Fixes a .row class collision with the command palette that broke row-header layout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Maximize screen usage per feedback: widen container to 1440, cut excess vertical padding, shrink the featured billboard, and densify library tiles (6/row on a 1366 Chromebook, 2-up on phone with the next peeking). Drop the redundant monogram from tiles (collided with the title on short tiles); title now sits on a bottom bar with ellipsis for long names. Add scroll-margin so anchored sections clear the sticky nav. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Ditch the generic nav bar for an iOS Dynamic Island: a compact centered glass pill (brand + live status) that morphs open on hover/tap to reveal the links, search, and theme toggle (springy width transition, ambient status collapses as controls expand). Merge the two search boxes into one — the island search / Cmd-K palette, which now also searches game titles. Tuned to fit on phones. Removes the duplicate library search. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Each nav tab gets an icon (Games=controller, Apps=grid, Proxy=globe, Privacy=lock); active tab icon tints with the accent. The island now collapses label text away below 900px so the pill reduces to icon-only on small laptops and phones, keeping it compact on small screens. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Per maintainer: remove Replit (nix + dead Replit DB dep); keep Vercel (split-deploy, already set); keep the about:blank cloak (opt-in, gesture- triggered, never auto-on) and the multi-tab in-app browser in 1.0 scope. Update BUILD_STATUS locked decisions + phase checklist accordingly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Per maintainer: ship a single engine (Scramjet) over Wisp for maximum LTS stability and bisectable bug reports. Ultraviolet stays a documented post-1.0 escape hatch, added only if the nightly live-site test proves a real compatibility gap. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Resolved with maintainer: - Accounts: public proxy + single admin gate (no user sign-ups) - Admin auth: pluggable adapter; will use forthcoming ZADMIN Auth system, env-password placeholder for 1.0 - Storage: better-sqlite3 (no MongoDB) - Deploy backend: Render (frontend stays on Vercel) - Music/Spotify slot: reserved for a future project integration (TBD) - Mirror/reachability: post-1.0 - LTS window: 6 months active + 6 security-only - Git history: leave intact, stop tracking big files going forward All Section 9 decisions now closed; BUILD_STATUS is the source of truth. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Per maintainer: do not do any ZADMIN work yet (not even an adapter). 1.0 ships a simple env-password admin gate; ZADMIN is a separate future project to be picked up only on the maintainer's go-ahead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
The working single-engine proxy pipeline: - Express serves the app + scramjet/bare-mux/epoxy browser bundles straight from node_modules (no guessed paths); raw node:http owns the 'upgrade' event so wisp-js routes /wisp/ tunnels, non-wisp upgrades dropped. - COOP same-origin + COEP require-corp on every response (cross-origin isolation for Scramjet WASM + epoxy). - One service worker (public/sw.js) via $scramjetLoadWorker. - Client (public/boot.js) registers the SW + sets the epoxy transport at /wisp/ eagerly on load, then navigates via the Scramjet controller. - envalid fail-fast config, pino logging, crash-only handlers that LOG (no process.exit mid-request), graceful shutdown. Pinned co-released set: scramjet 1.1.0, wisp-js 0.4.1, bare-mux 2.1.9, epoxy-transport 2.1.28 (2.x keeps the node epoxyPath helper). Verified locally: /healthz, COOP/COEP headers, all bundles 200, wisp handshake (101 / dropped), and a live HTTP site rendered fully-styled inside the Scramjet frame end-to-end. HTTPS blocked only by this dev sandbox's TLS MITM (epoxy correctly rejects the private CA) — confirm on first Render deploy. Includes zero-dep test/wisp-handshake.mjs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
…y UI Ports the approved design to an Astro 5 static MPA under v10/web/, served by the Phase 1 Express server (now serves web/dist/, falling back to public/ when unbuilt): - Liquid Glass, dark-first, with the Dynamic Island nav (per-tab icons, icon-only collapse), theme/accent/perf controls, command palette. - Netflix-style library over the REAL catalog: content collections (Astro 5 file() loader + Zod) built from V9's 284 games / 55 apps, featured billboard + side-scrolling shelves, real icons. - Proxy-integrated /go page: Liquid Glass multi-tab browser (tabs, address bar, always-visible Exit/quick-exit) reusing the verified Phase 1 Scramjet/Wisp wiring. - Settings/privacy pages with honest 'quiet on a shared screen' copy. Verified: astro build green (5 pages); home/apps/settings render; the new multi-tab go page proxied a live site (httpforever.com) end-to-end. Icons synced from committed static/ at build (prebuild) — not duplicated in git; dist/.astro/node_modules gitignored. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
…e.html) The showcase is a self-contained single-file build of the V10 UI with real catalog icons embedded as data URIs (~1.4MB) for the clickable Artifact. It's reproducible from the mockup + catalog, so keep it out of git rather than committing the heavy generated file. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
The Dynamic Island nav now switches between distinct pages — Games, Apps, Proxy, Privacy, Settings — instead of one long scroll, matching the real Astro MPA. Adds: a client-side router (showView) wired to the island links + brand + omnibox + palette; an Apps page (its own catalog + shelves); a Proxy page with a multi-tab browser mock (tab strip, address bar, always-there Exit); tiles now support real icon images (falling back to gradient). Settings gets its own nav entry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
- Home is now a clean, search-first page (centered logo + omnibox + Games/Apps/Surprise-me quick links), not a marketing lander; it's the default view. The Netflix library moves to its own Games page. - Proxy page rebuilt as a real browser: dropped the marketing heading, the tab strip + address bar + frame now fill the viewport edge-to-edge (no wasted space). - Content views get top padding so they clear the floating island. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Every view now fills the viewport with the footer anchored to the bottom instead of floating up mid-screen. Content-rich views (games/apps/settings) sit below the Dynamic Island and scroll; sparse views (home/privacy) center their content in a sticky-footer flex column. Settings was the emptiest screen — replaced the lone appearance bar with a three-card grid (Performance toggles, Privacy & exit, About/version) so it reads as a genuine settings page and has no dead space. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
… space Proxy view now reads like Google Chrome: real tab strip (rounded connected tabs, hover states, close affordances), a Chrome toolbar with circular nav buttons, a pill omnibox with a lock glyph, and a bookmark / menu / profile-avatar cluster. The empty content frame is replaced by a Chrome-style new-tab page — wordmark, search pill, and a grid of shortcut tiles — so the workspace fills the viewport instead of showing a lone centered note. Apps now mirrors Games: a featured billboard sits above the Netflix-style shelves so the page opens with the same weight as the game library. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Adds a packed, edge-to-edge grid of the entire catalog below the Netflix shelves on both library views (auto-fill columns, 6 on a 1280 screen / 9 on 1920), and widens the library column to 1780px so wide monitors aren't half-empty. Search hides the games grid so results stay clean. Work in progress under review — not final. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Home is no longer a lone centered search box: below the search hero it now carries real content shelves (Jump back in / Popular games / Top apps) that fill the page top to bottom. Proxy new-tab page top-aligns like real Chrome and gains a "Recently visited" card row, so the workspace fills instead of centering a small block in an empty frame. With the earlier dense All grids on games/apps and the three-card settings page, no view leaves a large empty band. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Revert the home content shelves — the Google-style centered lander (logo + search + quicklinks) was the intended design. Games/apps keep their dense grids and the proxy keeps its filled new-tab page; only home goes back to the minimal search-first landing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Bring the real app in line with the approved mockup (docs/design): - Home "/" is now the Google-style search lander (logo + omnibox + quick links); the games library moved to /games. Nav + ⌘K routes updated. - Games/Apps gain a dense full-width "All" grid below the Netflix shelves so wide screens fill edge to edge; dropped the in-library search field (search is unified into the ⌘K palette). Library column widened to 1780px. - /go proxy reskinned to look like Google Chrome — Chrome tab strip, pill omnibox with lock/globe, menu + profile avatar, and a Chrome-style new-tab page with shortcut tiles. The verified multi-tab Scramjet wiring (IDs, JS) is untouched; this is purely the skin + the full-height shell. - /settings rebuilt as the three-card grid (Performance / Privacy & exit / About); performance mode, tab disguise, and clear-traces stay wired. - Sticky-footer full-height layout across every page. Build green (6 routes); every page verified against src/server.js with no console errors and the proxy engine reaching "ready". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Complete the opt-in about:blank cloak on /privacy as a clean port of V8's proven createAboutBlank (static/assets/scripts/h.js), minus the V9 auto-run bug. The prior Phase-2 launcher only opened a blank window; this restores the three parts of the working V8 flow that make it an actual cloak: - redirect the ORIGIN tab to the decoy (sg:panicUrl) after launch, so nothing left on screen points back at SlowGuardian; - a beforeunload guard in the blank document so an accidental close asks first; - a Firefox guard (Firefox blocks scripting an about:blank popup) with an honest fallback message. Still gesture-triggered and opt-in (sg:aboutblank); the blank window loads SlowGuardian in a full-page iframe wearing the sg:cloak title/favicon. Copy updated to state plainly that this tab switches to the decoy and that it does not bypass network filtering or device monitoring. Verified end-to-end in headless Chromium: popup opens with the disguise title, iframe src = origin, beforeunload set, origin tab redirects to the decoy, no console errors. Mirror rotation stays post-1.0 per the locked decisions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Health & readiness:
- /healthz now returns {ok, version, uptime}; new /readyz returns 200/503
with a per-asset check list (proxy bundles + built frontend must actually
resolve). Load balancers gate on /readyz.
Proxy smoke test (Playwright, test/e2e.spec.mjs):
- Boots the real server (webServer waits on /readyz), asserts the lander and
games grid render, health + COOP/COEP headers, and — the key case — proxies
a LOCAL fixture end-to-end (SW → bare-mux → epoxy → wisp TCP → Scramjet),
so it never depends on live internet. 5/5 pass in headless Chromium.
- wisp-js blocks loopback/private IPs by default (SSRF hygiene); enabled
allow_loopback_ips ONLY under NODE_ENV=test so the fixture is reachable —
dev/prod stay locked (allow_private_ips stays false everywhere).
CI (.github/workflows/v10-ci.yml, scoped to v10/**, independent of the legacy
test-sw.yml): build frontend → install Chromium → wisp handshake → Playwright
e2e; plus a parallel docker-build job that builds the image (no push) so the
Dockerfile is validated on every change.
Docker (v10/Dockerfile): multi-stage — build Astro frontend, resolve prod-only
server deps (drops the test browser), slim runtime with a /readyz HEALTHCHECK
running as the node user. Builds from the repo root (the web build sources the
catalog icons from repo-root static/); .dockerignore added at the root.
Tooling: swap the unused puppeteer-core devDep for @playwright/test; add
build:web / test:wisp / test:e2e scripts; version 10.0.0-phase1 → 10.0.0-rc.1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Audited V9 against V10 and closed the real gaps (clean rebuilds, no bloat): - Onboarding: a one-time first-run modal (web/src/components/Onboarding.astro, rendered from Base) — welcome → appearance (theme+accent, applied live) → privacy (tab disguise / about:blank opt-in) → done; guard sg:onboarded. Uses the shared window.SG API so choices persist. Playwright-tested. - Search-engine choice: Settings picker (Google/Bing/DuckDuckGo/Startpage/ Brave/Ecosia/custom) → sg:engine template; both the lander and the proxy omniboxes honor it instead of hardcoding Google. - Tab-cloak presets expanded 4 → 12 (adds Slides, Gmail, Meet, Canvas, Schoology, Khan, Wikipedia, PowerSchool) alongside custom title/favicon. - Proxy utilities: Fullscreen + Open-in-new-window (Ctrl+T/W/L intentionally skipped — they collide with the host browser's own bindings). README rewritten with a transparent carried-over / intentionally-dropped / deferred map so nothing is silently lost. Legacy code preserved on the legacy/v8 and legacy/v9 branches. Build green (6 routes); Playwright 6/6 (adds a first-run onboarding test). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
https://slowguardian-v10.onrender.com is up and working: /healthz + /readyz all green, lander + onboarding render, and the proxy loaded a live HTTPS site (example.com) end-to-end through Wisp/Scramjet on a real network — closing the Phase 1 "re-confirm HTTPS on a real egress" caveat. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
- Settings: drop the marketing headings/jargon; present a plain labeled list (Appearance/Accent/Performance/Search/Tab disguise/Privacy/Clear/ Version) closer to V8/V9 — no "straight talk" copy, no section headers. - Remove the jargon footer globally (Base.astro). - Proxy (/go): make the in-app browser fullscreen — full-bleed edge to edge, fills the viewport top to bottom (thin gap for the floating island), no footer, no rounded box. Verified: shell spans full width, footer gone. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
…-style settings - Dynamic Island now docks to the top-left and shows icons only until hovered/focused/tapped, then morphs open to reveal labels (icon-only on phones). - Launching a game/app from the library opens the proxy in an immersive mode (?app=1): the tab strip, toolbar, status bar, and global nav island are all stripped, leaving a full-viewport view of just the content with a small floating control cluster (reload / fullscreen / quick-exit / close). - Settings rewritten as a plain card grid resembling V8/V9: one clear title + one-line description + control per card, no marketing copy or page heading. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
The previous change rewrote the shared Dynamic Island for every page. Restore the original centered island everywhere and move the left-docked, shield- collapsed (expands on hover/focus/tap) variant behind a .sg-proxy class that only go.astro sets — set synchronously in <head> so the pill never flashes centered first. Every non-proxy page keeps the original centered pill. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
The root vercel.json routed every request to index.js (V9's server), so the connected Vercel project only ever served V9 — V10 lives under v10/web and was never built. Replace the legacy builds/routes with a static build of the V10 Astro app (v10/web → dist); its prebuild syncs the catalog icons from the repo-root static/ tree, which Vercel has in the full clone. Note: the proxy still requires the persistent Wisp backend (Render); Vercel serves the static frontend only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
The privacy narrative read like a warning label. Removed it everywhere it appeared and replaced it with plain descriptions of what each control does: - privacy: delete the "Straight talk." callout; "Quiet on a shared screen." → "Privacy controls."; "Hide the address, honestly." → "Hide the address bar."; drop the about:blank caveat note and the clear-traces "can't touch records" sentence; rewrite the page meta description. - onboarding: "Quiet on a shared screen" → "Privacy", drop the "Straight talk:" fine print (and its now-dead .ob-fine rule). - proxy new-tab: delete the "not a way past network filtering" fine print. - docs: stop mandating the copy in README/BUILD_STATUS; the scope decision itself (no monitoring-evasion features) is unchanged. No replacement claims the product defeats filtering or monitoring — each line just says what the feature does. Verified: 0 matches for the removed phrasing across all 6 built pages; e2e 6/6. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
- go: the immersive Close pill inherited display:grid from .gg-immbtn, which stacked the X icon on top of the "Close" label so they overlapped inside a 32px box. Switch it to inline-flex with explicit sizing. Verified: icon and label now sit on one row (no overlap, label inside the pill), and it still collapses to a 32px round button at 390px wide. - Base: catalog icons that 404 rendered the browser's broken-image glyph. Add a capture-phase error handler that degrades a failed tile/billboard image to a lettered placeholder over the existing gradient. Covers tiles injected later by search and the palette. - apps: repoint 4 icons at the files that actually exist on disk (gemini.png, instagram.webp, ng.webp, snapchat.webp). - games: fix a malformed URL, "https:/moomoo.io" -> "https://moomoo.io". Found by a full catalog audit (339 entries HTTP-checked). e2e 6/6. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
CATALOG (full HTTP audit of all 339 entries, then re-verified independently): Root cause of most rot: github.com/3kh0/3kh0-assets was gutted and moved to GitLab, killing every raw.githack.com/3kh0/... link; f.silvergames.com and static.arcadespot.com stopped resolving; now.gg retired its iframe embed API. - 55 entries repointed at verified-200 replacements (glcdn.githack GitLab CDN, gamesfrog, coolmath /play embeds, archive.org /embed, author-renamed Pages). - 10 entries removed as genuinely unavailable (now.gg cloud-Android titles: Fortnite, Toca Boca x3, Stumble Guys, Bloons TD Battles, Cookie Run, Aptoide, Roblox NowGG.me, a deleted Replit). - 7 local games pointed at /y/... and /f/... assets that were never in the repo; all now have hosted URLs. - All 10 missing app icons resolved (4 repointed, 6 fetched). Result: 0 dead paths and 0 missing icons, from 86 hard-broken. The remaining 503s were confirmed to be this sandbox being rate-limited, not dead hosts (slither.io/kiomet.com return 200 after a pause), so those were left alone. UI (3 broken, 5 major — each reproduced and re-verified after the fix): - reveal animation: threshold 0.12 can never fire for an element taller than viewport/0.12, so the ~6000px "All" grid stayed at opacity 0 forever — 90% of /games was blank on a Chromebook viewport. Now threshold 0 + rootMargin. - onboarding: modal was taller than a short viewport with no scroll and no dismiss path, hiding Skip/Next. Now scrolls, with sticky actions. - palette: Library self-wired #cmdList and its focus handler overwrote Base's render, so Cmd-K always showed "No matches". Library now registers a source and Base owns the list; "mine" returns the Minecraft entries. - home omnibox: input lacked min-width:0, pushing the Open button out of the pill and off-screen at 390px. - tiles: square logo art was cover-cropped and decapitated; near-square art is now letterboxed onto the tile plate. - nav pill overlapped the library heading on phones; light-theme secondary text (2.6:1) and accent links (2.56:1) were under AA; palette had no surface and the toast was capped at 50vw and near-invisible. e2e 6/6. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
…fixes GAMES — the earlier pass only borrowed Interstellar's asset hosts to repair dead links; this actually adds their catalog. Interstellar doesn't store games, it proxies 3kh0-assets at request time, so I enumerated that tree directly (GitLab project 54213496, 412 dirs), diffed it against ours, and HTTP-verified every candidate: 412 slugs -> 65 already covered -> 347 candidates -> 306 verified playable -> 289 added after dropping dupes and 9 non-games (a Flash runtime, a prank "virus" page, utility folders). Names come from each game's own <title>, cleaned and length-capped. Games: 276 -> 565. Only 6% of those folders ship artwork, so rather than 273 broken-image tiles, an entry with no image now renders a deterministic gradient plate carrying its wordmark (catalog.ts artPlate + .art.noart) — no wasted 404 request per tile, and the grid reads as designed rather than failed. UI (continued from the previous commit): - billboard: it reused the small square catalog icon as a 5.5:1 hero, giving a ~9x upscaled blur. Now a blurred backdrop copy plus a crisp contained copy held clear of the text (hidden under 760px where there's no room). - verified in-browser: square logos are contained not decapitated, the All grid reveals (opacity 1), no horizontal overflow. e2e 6/6. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
/go UI — it was a browser with a floating nav pill parked on top of its own tab strip, and 54px of the viewport reserved for that pill: - hide the pill on /go entirely; the SlowGuardian logo now lives in the browser's own toolbar as the way back to the site, and leads the immersive control cluster too (logo · reload · fullscreen · quick-exit · Close) so both modes read the same way. - genuinely fullscreen: page starts at y=0, 100dvh. Chrome trimmed 100px -> 83px (tab strip 46->39, toolbar 54->44), content viewport 641 -> 684px at 768p. - the "+" sat ~1100px right of the last tab on a wide screen; it now docks beside them. Tabs get cursor:pointer. - drop the permanent full-width "ready" status bar for a transient corner bubble (idle now sets "", so :empty actually fires), stop stealing focus into the address bar on arrival (it painted a full-width blue ring), and raise the immersive cluster from 45% to 82% opacity since :hover never fires on touch. - mobile: hide forward/popout/fullscreen so the address bar gets the room. - remove dead .gg-menu/.gg-avatar rules and the stale .sg-proxy island offsets. PROXY ON A STATIC HOST — I previously said this was impossible; that was wrong, and the split was verified end-to-end before making the change. A static host cannot run /wisp/, but it can drive a remote one: - web/scripts/copy-proxy-assets.mjs (postbuild) ships scramjet/bare-mux/epoxy into dist so /scram /baremux /epoxy resolve same-origin off a static host. - PUBLIC_WISP_URL selects the wisp backend at build time, falling back to this origin so the single-service Render deploy is byte-identical. An https page with a ws:// value is upgraded to wss:// (mixed content is the easy mistake). - vercel.json now sets COOP/COEP (required, Vercel sets neither by default) and installs v10's deps so the copy step can resolve the packages. e2e 6/6 including the proxy round-trip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
epoxy's transport is loaded with a dynamic import(), so a non-JavaScript MIME on /epoxy/index.mjs would hard-fail the proxy. Vercel's mime-db maps .mjs to text/javascript and .wasm was observed correct on a live deploy, but the live check here was intercepted by Deployment Protection (assets 302 to the SSO login), so this pins both rather than relying on the default. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
Set PUBLIC_WISP_URL in the Vercel buildCommand, defaulting to the Render
service and still deferring to a dashboard env var if one is set
(${PUBLIC_WISP_URL:-...}). Verified both build paths:
vercel buildCommand -> "wss://slowguardian-v10.onrender.com/wisp/" inlined,
same-origin fallback constant-folded away
npm run build:web -> no Render host present, same-origin fallback intact
so the single-service Render deploy is unchanged. Render's /wisp/ was confirmed
to accept a wss upgrade carrying the Vercel Origin (HTTP 101, valid accept hash).
e2e 6/6.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
…hing Reported symptom: the address bar showed the requested site but the frame rendered SlowGuardian's own home page. Cause: sw.js had no install/activate handlers, and registerSW() only awaited navigator.serviceWorker.ready. .ready means a worker is ACTIVE, not that this page is CONTROLLED — a freshly installed worker does not control the page that registered it until that page reloads or the worker claims its clients. So on a first visit navigator.serviceWorker.controller was null, the first /scramjet/<url> request bypassed the SW and went to the network, and a static host answered it with index.html — i.e. our own lander inside the proxy frame. On Express the same request 404s, which is why this only showed up on Vercel. Fix: - sw.js: skipWaiting() on install, clients.claim() on activate. Also lets a new deploy displace a stale cached worker instead of waiting for every tab to close (which is why the reported page mixed old and new chrome). - go.astro: after .ready, wait for controllerchange when controller is still null, capped at 5s so a browser that never claims cannot hang the UI. - both copies of sw.js updated: web/public/sw.js is the one that ships to dist/; v10/public/sw.js is the server's Phase-1 fallback. Only the latter was edited first and the built output was unchanged — caught by testing the SERVED file rather than the source. Verified on a fresh browser profile against the built output: before -> FIRST VISIT controlled: false, frame showed our own page after -> FIRST VISIT controlled: true, frame title "FIXTURE PROXIED OK" e2e 6/6. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BzgycoxZ3LNqvFLv8r4SPg
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ground-up, LTS-focused rebuild of SlowGuardian, developed under
v10/so this PR is purely additive — V9 at the repo root is untouched. The V8 and V9 code is preserved on thelegacy/v8(a91599b, Version8.9a) andlegacy/v9(currentmain) branches before any future cutover.Version
10.0.0-rc.1. This lands the app + tests + CI + Docker; the 1.0 flip, GHCR publish, and the actual root cutover are deliberately left as a follow-up.What's inside
wisp-js), a single service worker,bare-mux+epoxy-transport, COOP/COEP cross-origin isolation. Express on a rawnode:httpserver, crash-only, envalid config, pino logging. Bundles are served straight fromnode_modulesso the bytes always match the installed version./go) — Chrome-style multi-tab in-app browser (tab strip, pill omnibox, fullscreen, open-in-new-window, always-there Quick Exit, Chrome-style new-tab page).createAboutBlank, minus the V9 auto-run bug), and clear-traces.Phases (all verified)
/healthz+/readyz, Playwright smoke test, CI, Docker.Testing / CI / Docker
npm run test:e2e— Playwright, 6/6: lander, library, health, COOP/COEP, first-run onboarding, and a full proxy round-trip against a local fixture (SW → bare-mux → epoxy → wisp → Scramjet), so it never depends on live internet.npm run test:wisp— zero-dep/wisp/upgrade handshake..github/workflows/v10-ci.yml— build frontend → Chromium → wisp handshake → Playwright e2e, plus a parallel docker-build job. Scoped tov10/**, independent of the legacytest-sw.yml.v10/Dockerfile— multi-stage, non-root,/readyzHEALTHCHECK. Build from the repo root:docker build -f v10/Dockerfile -t slowguardian:10 .Intentionally not carried over from V9
Full transparency map in
v10/README.md. In short (all previously agreed): one proxy engine only (dropped UV / Dynamic / Rammerhead / failover), no accounts / premium / ads / KeyAuth (public proxy + single env-password admin gate; ZADMIN is a separate future project), no MongoDB (embedded SQLite), no monitoring-evasion (privacy defends against a shoulder-glance, not network/device monitoring — and the UI says so), music/Spotify reserved for a future integration, and the theme-zoo / particles / plugins / movable-buttons / 100-feature-manager / home widgets superseded by the approved Liquid-Glass design.Deploy
Split: static frontend on Vercel, persistent Wisp backend on Render; one Docker image is the canonical artifact. Re-confirm HTTPS proxying on the first real deploy (a TLS-intercepting dev egress correctly fails epoxy's cert validation).
🤖 Generated with Claude Code
Generated by Claude Code