From 661d0387e04fc2b8a0534525cf165bbcb70e2464 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 14:56:19 +0200 Subject: [PATCH 01/31] chore(release): prepare 0.5.1 metadata --- CHANGELOG.md | 51 +++++++++++++++++------------------------------ Cargo.lock | 10 +++++----- Cargo.toml | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 27 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3369a2d..bd5b2e79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,45 +5,29 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch ## [Unreleased] -### Changed - -- Notifications coalesce refreshes from opening the page and regaining focus. Marking the list seen does not queue another read: only changed notification times refresh its rows, so a delayed duplicate cannot start after the tab is hidden. - -- On phones, header search has a full-width second row, leaving Home, the online count, Settings and account controls in view. A wrapped reply's app link clears its collapse button's full tap area. - -- Front-page feeds remember casts actually read for a second with at least half its possible viewport exposure visible in a foreground tab, including cards taller than the screen. Later feed generations leave these posts out, with Show seen posts below the list and Reset seen posts in Settings. History stays in this browser, separate for each signed-in FID and signed-out reader, bounded to 2,000 hashes for 30 days across four readers. Current cards stay put while read, and direct posts, profiles and threads remain complete. +## [0.5.1] - 2026-10-23 -- Show mini app casts moved out of the feed into a Settings panel in the header (for every reader, signed in or not): the "N mini app casts hidden" line is removed, and the account menu no longer repeats the switch. A shown mini app cast quoted in another cast now carries its "Open in Farcaster" link inside the quote card; no other cast or quote shows mini app chrome. Quoted mini apps follow the switch in place; early cards end before a shown mini app so the app takes over without replacing it with different markup. - -- The "Only N casts in …" note sits under a range's list, where it ends, not above it: it came once the list had ended and moved every card down (a layout shift at 1280). -- The front page has two tabs for a signed-in reader, as on X: **For you** and **Following**, links in place of the Following / Everyone menu, each 44 px tall. For you, the default, is the trending pool with the casts of the accounts you follow lifted: 20 times their points in hot and 6 in top (`FOLLOWED_HOT_WEIGHT`, `FOLLOWED_TOP_WEIGHT`), and new stays in time order. Following (`?feed=following`) is only their casts, in hot, new and top and over the time range, with no trending casts topping it up any more. Old `?feed=everyone` links open For you. For you costs no extra request while it is drawn: it ranks by the accounts kept from your last Following page, renewed by one background read at most every 10 minutes. Signed out, the front page has no tabs, as before; early paint draws a signed-in reader's For you, tabs and all. +### Changed -- Messages now only take verified Farcaster accounts: allthing.social's attestation key is set up (the `ATTEST_KEY` secret) and its public half, `5df241b6517235a521769788541a5cb6369bb3deb4536734b5db8b5cb23d87cb`, is pinned in the SpacetimeDB module (`spacetime/spacetimedb/src/attest_key.rs`), as `/api/v1/status` reports. Signed in, Messages verifies your account before you chat or send a message; no one can speak there as someone else's FID. +- **For you and Following.** Signed-in readers have two front-page tabs, each with hot, new and top and every time range. For you lifts casts from accounts you follow; Following shows their casts only. New stays chronological, including with Favorite and Show less. +- **Seen posts.** Later front-page visits leave out casts you read for a second in a visible tab, including cards taller than the screen. Show seen posts brings them back, and Reset seen posts clears the history in Settings. History stays in this browser, separate for each reader: at most 2,000 hashes for 30 days, across four readers. Cards stay put while you read; direct posts, profiles and threads stay complete. +- **Mini apps in Settings.** Show mini app casts is in the header's Settings panel for every reader, replacing the feed's hidden-cast count and switch. Only casts and quotes that contain mini apps show their Open in Farcaster links, and quoted mini apps follow the setting immediately. +- **A clearer header.** Phone search has a full-width second row, keeping Home, the online count, Settings and account controls in view. The online count reserves its space on desktop and stays beside Home on phones. +- **Verified Messages.** Messages verifies the signed-in Farcaster account before it can chat or send messages. The Worker's attestation key is pinned in the SpacetimeDB module, which rejects forged and expired attestations. ### Fixed -- Feed-ranking checks restore read posts through Show seen posts even when the filtered list is empty or a delayed navigation is still loading. - -- Reply-composer geometry checks wait for its entrance animation before measuring exact thumbnail and tool sizes, while retaining first-frame focus and layout-shift checks. - -- Pressed conversation rows keep their preview text and timestamps readable while the press animation dims the row, including on its selected background. -- The smoothness fixture locates the first feed card below both front-page tab rows before measuring navigation; its existing timing, frame and scroll-restoration budgets are unchanged. - -- Messages connects under the site’s existing Content Security Policy. SpacetimeDB’s product and sum codecs now use cached closures instead of compiling JavaScript strings; the SDK version is guarded at build time, and a browser test exercises the actual bundled connection, row decoding, account verification and chat sending under the production policy. - -- Following sort links and time-range changes prefetch their existing private feed, rather than fetching and waiting for unrelated For you home/latest payloads. -- The desktop online count reserves its width before loading, including at 921 px with Settings present, so the search box cannot overlap it. Phone layouts keep the compact dot and count at the 920 px breakpoint. - -- Following stops automatic pagination once its source reaches the selected time limit, and retains that cursor so a wider range resumes correctly. A fully seen or otherwise filtered feed reads at most ten payloads before offering Load more posts; each explicit press permits ten more. - -- Local macOS Worker and static Pages builds discover worker-build's cached `wasm-opt` under `Library/Caches`, so the browser modules receive the same optimization as CI. An explicit optimizer or one on PATH takes precedence, and cached binaries for other architectures are skipped. - -- Both front-page tabs keep the time selector in New and apply the selected range consistently. New stays strictly chronological even for favorites and accounts shown less. Changing the signed-in account replaces its feed and ranking snapshot; background follow reads and their ten-minute retry cap are scoped to that account, and late answers from the old account cannot refill its private cache. -- The online count stays visible beside Home on phones, with its space reserved before loading. Showing oneself or signing in replaces the browser's anonymous presence instead of counting it twice; hiding or signing out removes the public name, including from later cached responses at other locations. Beat jitter only delays the advertised interval by up to 30 seconds, within the online grace, instead of beating too early or expiring a reader too soon. +- Short time ranges include newly posted casts even while Hypersnap's trending list lags behind. Every sort keeps the chosen range, and the end-of-range note appears below the list without moving cards down. +- Following prefetches its own feed when changing sort or range, stops automatic paging at the time limit, and resumes from that cursor for a wider range. A fully seen or filtered feed offers Load more posts after ten payloads rather than reading indefinitely. +- Changing accounts replaces the feed and ranking snapshot, and late answers from the previous account cannot refill its cache. Presence no longer counts an anonymous and signed-in visit twice; hiding or signing out also removes the public name from cached lists. +- Messages connects under the existing Content Security Policy without permitting JavaScript evaluation. Pressed conversation rows keep their previews and timestamps readable. +- Notifications coalesce refreshes from opening the page and regaining focus. Marking the list read no longer queues a duplicate request that could start after the tab is hidden. +- A wrapped reply's app link clears the collapse button's full tap area. +### Development -- `scripts/attest-key.mjs` writes a public key that compiles: its pattern stopped at the `;` inside the placeholder `[0; 32]`, leaving `[0x…]; 32];` in `attest_key.rs`. It now replaces the whole array, also once a key is pinned over several lines. -- Every time range up to 7 days holds the casts just posted. Hypersnap's trending lists run 4 to 6 hours behind (its past hour's list was 5 to 6 hours old, so Past hour could come back empty), so a range's first page adds the newest casts the cron stores each minute, kept to the range. +- Local macOS builds find worker-build's cached WebAssembly optimizer. SDK wire-format and strict-CSP browser checks cover Messages; feed-ranking, reply-composer and smoothness fixtures exercise the updated UI without changing their budgets. +- The attestation-key helper replaces the complete Rust key array, including multiline values, so a generated key compiles. ## [0.5.0] - 2026-10-22 @@ -595,7 +579,8 @@ Released before tagging began; the link points to its last commit, `e521cd1`. - A read-only Next.js prototype with live Hypersnap data, on GitHub Pages. -[Unreleased]: https://github.com/ael-dev3/Allthing/compare/v0.5.0...HEAD +[Unreleased]: https://github.com/ael-dev3/Allthing/compare/v0.5.1...HEAD +[0.5.1]: https://github.com/ael-dev3/Allthing/compare/v0.5.0...v0.5.1 [0.5.0]: https://github.com/ael-dev3/Allthing/compare/v0.4.0...v0.5.0 [0.4.0]: https://github.com/ael-dev3/Allthing/compare/v0.3.0...v0.4.0 [0.3.0]: https://github.com/ael-dev3/Allthing/compare/v0.2.0...v0.3.0 diff --git a/Cargo.lock b/Cargo.lock index 4d317452..76269df2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,7 +23,7 @@ dependencies = [ [[package]] name = "allthing-core" -version = "0.5.0" +version = "0.5.1" dependencies = [ "blake3", "chacha20poly1305", @@ -37,7 +37,7 @@ dependencies = [ [[package]] name = "allthing-data" -version = "0.5.0" +version = "0.5.1" dependencies = [ "allthing-core", "futures", @@ -47,7 +47,7 @@ dependencies = [ [[package]] name = "allthing-web" -version = "0.5.0" +version = "0.5.1" dependencies = [ "allthing-core", "allthing-data", @@ -66,7 +66,7 @@ dependencies = [ [[package]] name = "allthing-worker" -version = "0.5.0" +version = "0.5.1" dependencies = [ "allthing-core", "allthing-data", @@ -2753,7 +2753,7 @@ dependencies = [ [[package]] name = "xtask" -version = "0.5.0" +version = "0.5.1" dependencies = [ "allthing-core", "wasm_split_cli_support", diff --git a/Cargo.toml b/Cargo.toml index 03f6f074..8ec7b7b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ exclude = ["spacetime/spacetimedb"] resolver = "3" [workspace.package] -version = "0.5.0" +version = "0.5.1" edition = "2024" rust-version = "1.99" license = "AGPL-3.0-or-later" diff --git a/package-lock.json b/package-lock.json index 1df13c52..85260221 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "allthing", - "version": "0.5.0", + "version": "0.5.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "allthing", - "version": "0.5.0", + "version": "0.5.1", "license": "AGPL-3.0-or-later", "devDependencies": { "@playwright/test": "1.56.1", diff --git a/package.json b/package.json index 3c206c0a..ebc228ef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "allthing", - "version": "0.5.0", + "version": "0.5.1", "private": true, "description": "Allthing: a read-only Farcaster client in Rust, served from a Cloudflare Worker.", "license": "AGPL-3.0-or-later", From 11f3b72d6c9c1eb3e15b8a20ddd317901182449d Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 15:29:16 +0200 Subject: [PATCH 02/31] docs: align contributing rules with sign-in and mini apps --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 531e0391..9cece43c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,8 +7,8 @@ Everyone taking part is expected to follow the [code of conduct](CODE_OF_CONDUCT ## Ground rules -- **Reads, and the reader's own likes, recasts, casts, follows and deletions.** Don't add other ways to sign in, wallet connections or anything else that writes to Farcaster unless that scope has been agreed in an issue first. The one sign-in is Sign In With Farcaster by QR code ([docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#sign-in)); a reader's likes, recasts, casts, follows and deletions are signed in their browser, with a key they approved in the Farcaster app ([docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#liking-and-recasting)). -- **Never hide content** because of who posted it: Allthing shows no account labels. Casts with mini apps or frames, and spam by the fixed rules in `allthing-core/src/spam.rs`, are left out server-side (`Cast::hidden`, `thread::without_hidden`, `thread::prune_hidden`), and new list endpoints must do the same. +- **Reads, and the reader's own likes, recasts, casts, follows and deletions.** Don't add other ways to sign in, wallet connections or anything else that writes to Farcaster unless that scope has been agreed in an issue first. Where the Worker endorses keys, one approval in the Farcaster app signs the reader in and permits writing, by QR code on a computer or a link on a phone; Sign In With Farcaster by QR code is the fallback where it does not ([docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#sign-in)). A reader's likes, recasts, casts, follows and deletions are signed in their browser, with a key they approved in the Farcaster app ([docs/ARCHITECTURE.md](docs/ARCHITECTURE.md#liking-and-recasting)). +- **Never hide content** because of who posted it: Allthing shows no account labels. Spam by the fixed content rules in `allthing-core/src/spam.rs` is left out server-side (`thread::without_spam`, `thread::prune_spam`). Mini app and frame casts are marked with `Cast.mini_app` and kept in feed, profile, channel and thread payloads; the browser hides them unless Show mini app casts is enabled in Settings, and never runs them. Search, reply previews and notifications still drop both spam and mini apps (`Cast::hidden`). New list endpoints must follow one of these documented paths. - **Stay within the Free plan.** Each page view makes one API call. The Worker has a 10 ms CPU limit and at most 45 subrequests per invocation, cache calls included. New upstream calls go through `allthing-data/src/upstream.rs` (token buckets, breaker, timeouts) and payloads through `cache::serve`. Update [docs/BUDGET.md](docs/BUDGET.md) when the costs change. - **Put code where it belongs.** Pure logic and data types go in `allthing-core`, with unit tests. Provider quirks stay in `allthing-data/src/hypersnap.rs` and `allthing-core/src/normalize.rs`. The page builders in `allthing-data` also run in the browser for the static copy, so they reach the network only through the `Host` trait. UI goes in `allthing-web`, and its links are built with the helpers in `allthing-web/src/util.rs` (and opened from code with `use_go` there), because the static copy lives under `/Allthing`. - **Keep it fast.** Stay within the budget in [docs/PERFORMANCE.md](docs/PERFORMANCE.md), and send prefetches through `api::prefetch`. From f69a5c2390f885c6eae5eadecbf3dc08fb63d47c Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 16:27:18 +0200 Subject: [PATCH 03/31] test(perf): retain sanitized cold-load diagnostics --- CHANGELOG.md | 1 + docs/PERFORMANCE.md | 2 + e2e/helpers/perf-diagnostics.ts | 90 ++++++++++++++++++++++++++++ e2e/perf-diagnostics.fixture.spec.ts | 33 ++++++++++ e2e/perf.spec.ts | 47 +++++++++++---- 5 files changed, 160 insertions(+), 13 deletions(-) create mode 100644 e2e/helpers/perf-diagnostics.ts create mode 100644 e2e/perf-diagnostics.fixture.spec.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index bd5b2e79..09278b74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch ### Development +- Cold-load performance checks retain sanitized per-sample LCP, network, cache and long-task diagnostics, including on failure. Their timing limits, cold contexts and sample count are unchanged. - Local macOS builds find worker-build's cached WebAssembly optimizer. SDK wire-format and strict-CSP browser checks cover Messages; feed-ranking, reply-composer and smoothness fixtures exercise the updated UI without changing their budgets. - The attestation-key helper replaces the complete Rust key array, including multiline values, so a generated key compiles. diff --git a/docs/PERFORMANCE.md b/docs/PERFORMANCE.md index 1c35f8e3..9a92189a 100644 --- a/docs/PERFORMANCE.md +++ b/docs/PERFORMANCE.md @@ -15,6 +15,8 @@ Navigation should feel instant: a post opens as soon as it is clicked, the feed The CI `perf` job runs `e2e/perf.spec.ts` against https://allthing.social after every push to `main` (and on demand through `workflow_dispatch`). Before measuring, it waits for `/version` to report the checked-out commit (the triggering commit for a push, or current `main` for a manual run), or a later commit on `main` that includes it. Workers Builds skips a commit that a newer push supersedes: of five merges made within 33 seconds on 19 October 2026 it built the first and the last, so a commit can be live only as part of a later one, which the job tells from the repository's history. It polls every 10 seconds for at most 30 minutes, aborts an individual version read after five seconds, and fails without benchmarking if that release never arrives. Workers Builds takes 6 to 16 minutes from a push until the commit is live, and about 25 when a second merge queues behind the first: the five-minute wait it replaced gave up 21 seconds before #144 went live on 19 October 2026, and from its introduction (#133) the job failed on every push to `main` it ran for, without measuring anything. This keeps a pending deployment from passing the budget with the previous release's results. +Each cold-home sample logs its first-card and LCP times, the LCP element and image dimensions/loading hints, navigation and resource phases, cache/Server-Timing metadata, and main-thread long tasks. The JSON attachment `home-lcp-diagnostics.json` is retained even when readiness or the budget fails. URLs retain only origin and pathname; credentials, query strings, fragments and Server-Timing descriptions are omitted. Cross-origin timing phases can be zero when the image host sends no Timing-Allow-Origin header. These observations add no warm-up fetch, wait, cache override or resource priority change: the same three cold contexts and 1.5-second median budget apply. + ## Smoothness How the app answers a reader's taps, clicks and scrolls: `e2e/smoothness.fixture.spec.ts`, which CI's browser job runs on every pull request and push to `main`, on the local build with the Worker's API, the node and the images as stand-ins (the API answers after 60 to 180 ms). A signed-in reader with an approved key, on a phone (390 × 844, touch, the CPU slowed 2×) and on a computer (1280 × 900, a mouse): diff --git a/e2e/helpers/perf-diagnostics.ts b/e2e/helpers/perf-diagnostics.ts new file mode 100644 index 00000000..b9fb2ee0 --- /dev/null +++ b/e2e/helpers/perf-diagnostics.ts @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +import type { Page } from "@playwright/test"; + +/** URLs in reports never retain credentials, queries, fragments or data bodies. */ +export function safePerfUrl(raw: string): string { + try { + const url = new URL(raw); + return /^https?:$/.test(url.protocol) ? url.origin + url.pathname : `${url.protocol}[omitted]`; + } catch { return "[invalid URL]"; } +} + +/** Observe without warming, blocking, fetching or changing browser priorities. */ +export function perfDiagnosticsProbe() { + const state = ((window as any).__allthingPerfDiagnostics = { lcp: null as any, appCast: 0, longtasks: [] as any[] }); + new MutationObserver((_, observer) => { + if (document.querySelector("#app .cast-card:not(.skeleton)") && !document.querySelector("#boot[data-painted]")) { + state.appCast = performance.now(); + observer.disconnect(); + } + }).observe(document, { childList: true, subtree: true }); + new PerformanceObserver((list) => { + for (const entry of list.getEntries() as any[]) { + const element = entry.element as HTMLImageElement | null; + state.lcp = { + time: entry.startTime, render: entry.renderTime, load: entry.loadTime, size: entry.size, url: entry.url, + element: element ? { tag: element.tagName, classes: element.getAttribute("class"), parentClasses: element.parentElement?.getAttribute("class"), loading: element.getAttribute("loading"), priority: element.getAttribute("fetchpriority"), width: element.getAttribute("width"), height: element.getAttribute("height"), naturalWidth: element.naturalWidth, naturalHeight: element.naturalHeight } : null, + }; + } + }).observe({ type: "largest-contentful-paint", buffered: true }); + new PerformanceObserver((list) => { + for (const entry of list.getEntries()) { + if (state.longtasks.length < 100) state.longtasks.push({ start: entry.startTime, duration: entry.duration }); + } + }).observe({ type: "longtask", buffered: true }); +} + +/** Descriptions can contain URLs; retain only metric names and numeric durations. */ +export function perfServerTiming(raw?: string) { + return (raw ?? "").split(",").flatMap((part) => { + const name = part.trim().match(/^([A-Za-z0-9_-]+)/)?.[1]; + if (!name) return []; + const duration = Number(part.match(/;\s*dur=([0-9.]+)/)?.[1] ?? 0); + return [{ name, duration: Number.isFinite(duration) ? duration : 0 }]; + }); +} + +type ResponseTiming = { url: string; status: number; cache?: string; cfCache?: string; age?: string; serverTiming: ReturnType; colo?: string }; + +/** A bounded metadata log, read from the response event's existing headers. */ +export function perfResponses(page: Page): ResponseTiming[] { + const log: ResponseTiming[] = []; + page.on("response", (response) => { + if (log.length >= 256) return; + const headers = response.headers(); + const colo = headers["cf-ray"]?.split("-").pop(); + log.push({ url: safePerfUrl(response.url()), status: response.status(), cache: headers["x-allthing-cache"], cfCache: headers["cf-cache-status"], age: headers.age, serverTiming: perfServerTiming(headers["server-timing"]), colo: colo && /^[A-Z]{3}$/.test(colo) ? colo : undefined }); + }); + return log; +} + +/** Resource phases use navigation-relative milliseconds; zero can mean missing TAO. */ +export async function readPerfDiagnostics(page: Page, responses: ResponseTiming[]) { + const sample = await page.evaluate(() => { + const state = (window as any).__allthingPerfDiagnostics; + const navigation = performance.getEntriesByType("navigation")[0] as PerformanceNavigationTiming; + const resources = performance.getEntriesByType("resource") as PerformanceResourceTiming[]; + const resource = (entry: PerformanceResourceTiming) => ({ + url: entry.name, kind: entry.initiatorType, start: entry.startTime, request: entry.requestStart, + response: entry.responseStart, end: entry.responseEnd, duration: entry.duration, + transferBytes: entry.transferSize, encodedBytes: entry.encodedBodySize, decodedBytes: entry.decodedBodySize, + serverTiming: entry.serverTiming.map(({ name, duration }) => ({ name, duration })), + }); + return { + navigation: { start: navigation.startTime, dnsStart: navigation.domainLookupStart, dnsEnd: navigation.domainLookupEnd, connectStart: navigation.connectStart, tlsStart: navigation.secureConnectionStart, connectEnd: navigation.connectEnd, request: navigation.requestStart, response: navigation.responseStart, end: navigation.responseEnd, dom: navigation.domContentLoadedEventEnd, load: navigation.loadEventEnd }, + lcp: state.lcp, + appCast: state.appCast, + lcpResource: resources.find((entry) => entry.name === state.lcp?.url) ? resource(resources.find((entry) => entry.name === state.lcp.url)!) : null, + resources: resources.filter((entry) => new URL(entry.name).origin === location.origin && /\/api\/v1\/home|\.wasm|\.(?:js|css|woff2)(?:\?|$)/.test(entry.name)).map(resource), + longtasks: state.longtasks, + }; + }); + const cleanResource = (entry: NonNullable) => ({ ...entry, url: safePerfUrl(entry.url) }); + return { + ...sample, + lcp: sample.lcp ? { ...sample.lcp, url: sample.lcp.url ? safePerfUrl(sample.lcp.url) : "" } : null, + lcpResource: sample.lcpResource ? cleanResource(sample.lcpResource) : null, + resources: sample.resources.map(cleanResource), + responses, + }; +} diff --git a/e2e/perf-diagnostics.fixture.spec.ts b/e2e/perf-diagnostics.fixture.spec.ts new file mode 100644 index 00000000..d889a26d --- /dev/null +++ b/e2e/perf-diagnostics.fixture.spec.ts @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +import { expect, test } from "@playwright/test"; +import { readFileSync } from "node:fs"; +import { perfDiagnosticsProbe, perfResponses, readPerfDiagnostics, safePerfUrl } from "./helpers/perf-diagnostics"; + +test("cold-load diagnostics retain LCP, resource phases and cache evidence without URL credentials or queries", async ({ page }) => { + expect(safePerfUrl("https://reader:password@example.com:8443/a/b?token=secret#private")).toBe("https://example.com:8443/a/b"); + expect(safePerfUrl("data:image/png;base64,private")).toBe("data:[omitted]"); + expect(safePerfUrl("not a URL")).toBe("[invalid URL]"); + const responses = perfResponses(page); + await page.addInitScript(perfDiagnosticsProbe); + await page.route("**/__perfdiag?*", (route) => route.fulfill({ contentType: "text/html", body: '

A cold-load diagnostic fixture

' })); + await page.route("**/__perfdiag.css?*", (route) => route.fulfill({ contentType: "text/css", body: "body{margin:0}img{display:block}" })); + await page.route("**/__perfdiag.png?*", (route) => route.fulfill({ contentType: "image/png", body: readFileSync("web/pfp.png") })); + await page.route("**/api/v1/home?*", (route) => route.fulfill({ json: { pool: [] }, headers: { "x-allthing-cache": "fresh", "cf-cache-status": "HIT", "cf-ray": "fixture-BEG", "server-timing": 'fresh;dur=3;desc="https://user:private@example.com/?header-secret"' } })); + await page.goto("/__perfdiag?document-secret"); + await page.evaluate(async () => { await (await fetch("/api/v1/home?api-secret")).json(); }); + await expect.poll(() => page.evaluate(() => (window as any).__allthingPerfDiagnostics.lcp?.element?.tag), { timeout: 5000 }).toBe("IMG"); + // A real main-thread pause: its observation must survive in the report. + await page.evaluate(() => { setTimeout(() => { const end = performance.now() + 80; while (performance.now() < end) {} }, 0); }); + await expect.poll(() => page.evaluate(() => (window as any).__allthingPerfDiagnostics.longtasks.length), { timeout: 5000 }).toBeGreaterThan(0); + const result = await readPerfDiagnostics(page, responses); + expect(result.lcp.time).toBeGreaterThan(0); + expect(result.appCast).toBeGreaterThan(0); + expect(result.lcp.element.tag).toBe("IMG"); + expect(result.lcpResource?.url).toMatch(/\/__perfdiag\.png$/); + expect(result.navigation.response).toBeGreaterThan(0); + expect(result.resources.some((resource) => resource.url.endsWith("/api/v1/home") && resource.end >= resource.start)).toBe(true); + expect(result.responses.find((response) => response.url.endsWith("/api/v1/home"))).toMatchObject({ cache: "fresh", cfCache: "HIT", colo: "BEG", serverTiming: [{ name: "fresh", duration: 3 }] }); + expect(result.longtasks.some((task: { duration: number }) => task.duration >= 50)).toBe(true); + const serialized = JSON.stringify(result); + expect(serialized).not.toMatch(/secret|password|private|reader:/); +}); diff --git a/e2e/perf.spec.ts b/e2e/perf.spec.ts index 5c72346d..c1c487ba 100644 --- a/e2e/perf.spec.ts +++ b/e2e/perf.spec.ts @@ -1,5 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-or-later import { expect, test, type Page } from "@playwright/test"; +import { perfDiagnosticsProbe, perfResponses, readPerfDiagnostics } from "./helpers/perf-diagnostics"; /* * Performance budget (docs/PERFORMANCE.md), measured in the browser: @@ -47,20 +48,40 @@ async function lcp(page: Page): Promise { } test.describe("performance budget", () => { - test("home LCP stays under 1.5 s (cold, median of 3)", async ({ browser }) => { + test("home LCP stays under 1.5 s (cold, median of 3)", async ({ browser }, testInfo) => { const samples: number[] = []; - for (let i = 0; i < 3; i++) { - const context = await browser.newContext({ viewport: { width: 1280, height: 900 } }); - const page = await context.newPage(); - await page.addInitScript(firstCastProbe); - await page.goto("/"); - await expect(page.locator("#app .cast-card:not(.skeleton)").first()).toBeVisible(); - await page.waitForTimeout(300); - // The page's largest content is the feed: count it from when the first - // cast appears, even if the browser's LCP entry picked something earlier. - const firstCast = await page.evaluate(() => (window as any).__firstCast as number); - samples.push(Math.max(await lcp(page), firstCast)); - await context.close(); + const diagnostics: unknown[] = []; + try { + for (let i = 0; i < 3; i++) { + const context = await browser.newContext({ viewport: { width: 1280, height: 900 } }); + try { + const page = await context.newPage(); + const responses = perfResponses(page); + await page.addInitScript(firstCastProbe); + await page.addInitScript(perfDiagnosticsProbe); + try { + await page.goto("/"); + await expect(page.locator("#app .cast-card:not(.skeleton)").first()).toBeVisible(); + await page.waitForTimeout(300); + // Keep the existing budget: the later of browser LCP and first cast. + const firstCast = await page.evaluate(() => (window as any).__firstCast as number); + const browserLcp = await lcp(page); + const value = Math.max(browserLcp, firstCast); + samples.push(value); + const detail = { sample: i + 1, value, firstCast, browserLcp, ...await readPerfDiagnostics(page, responses) }; + diagnostics.push(detail); + console.log(`LCP diagnostic ${JSON.stringify(detail)}`); + } catch (error) { + // Capture the last pipeline state even if readiness itself fails. + const detail = { sample: i + 1, incomplete: true, ...await readPerfDiagnostics(page, responses).catch(() => ({ responses })) }; + diagnostics.push(detail); + console.log(`LCP diagnostic ${JSON.stringify(detail)}`); + throw error; + } + } finally { await context.close(); } + } + } finally { + await testInfo.attach("home-lcp-diagnostics.json", { body: JSON.stringify({ budget: LCP_BUDGET, samples: diagnostics }, null, 2), contentType: "application/json" }); } const value = median(samples); console.log(`LCP samples ${samples.map((s) => s.toFixed(0)).join(", ")} ms; median ${value.toFixed(0)} ms`); From bec9420d31ef7c9f03fe9d089552564f289dd3a0 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 16:34:31 +0200 Subject: [PATCH 04/31] fix(post): react to mini-app visibility changes --- CHANGELOG.md | 2 + crates/allthing-web/src/pages/post.rs | 66 +++++++++++++++------------ e2e/mini-apps.fixture.spec.ts | 46 +++++++++++++++++++ 3 files changed, 85 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09278b74..491762da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch ### Fixed +- A directly opened mini app post follows Show mini app casts immediately in both directions, without a reload or refetch. Hiding it removes its body and embedded content while retaining its Open in Farcaster link; ordinary posts keep their content. + - Short time ranges include newly posted casts even while Hypersnap's trending list lags behind. Every sort keeps the chosen range, and the end-of-range note appears below the list without moving cards down. - Following prefetches its own feed when changing sort or range, stops automatic paging at the time limit, and resumes from that cursor for a wider range. A fully seen or filtered feed offers Load more posts after ten payloads rather than reading indefinitely. - Changing accounts replaces the feed and ranking snapshot, and late answers from the previous account cannot refill its cache. Presence no longer counts an anonymous and signed-in visit twice; hiding or signing out also removes the public name from cached lists. diff --git a/crates/allthing-web/src/pages/post.rs b/crates/allthing-web/src/pages/post.rs index 7ccda92c..916339e9 100644 --- a/crates/allthing-web/src/pages/post.rs +++ b/crates/allthing-web/src/pages/post.rs @@ -296,12 +296,7 @@ async fn newer_replies(hash: &str, want: u64) { } #[component] -fn MainCast(mut cast: Cast, notes: Notes, payload: Arc) -> impl IntoView { - // A mini app cast, for a reader who leaves them out: who and when, and - // that it is one (spam comes emptied already). - if crate::miniapps::hides(&cast) { - cast.strip_hidden(); - } +fn MainCast(cast: Cast, notes: Notes, payload: Arc) -> impl IntoView { // Whether the reader liked and recasted this cast, which may be older // than their latest likes and recasts. #[cfg(not(feature = "static-host"))] @@ -319,6 +314,41 @@ fn MainCast(mut cast: Cast, notes: Notes, payload: Arc) -> impl Int let href = user_href(&author.username); let gone = crate::components::deleted(&cast.hash); let (pfp, name, username) = (author.pfp_url.clone(), author.name().to_owned(), author.username.clone()); + // Keep the carried content intact so Settings can reveal it again. Only + // mini app bodies track this preference; ordinary posts keep their media. + let body_cast = cast.clone(); + let body_notes = notes.clone(); + let body_payload = payload.clone(); + let body = move || { + let cast = &body_cast; + let shown = !cast.mini_app || crate::miniapps::shown(); + if cast.hidden_for(shown) { + let note = if cast.spam { + "Post hidden: Allthing leaves out posts with links to vercel.app apps, gig-bot, DEGEN reward or airdrop bait, and DEGEN staking promotions." + } else { + "Mini app post hidden: Allthing does not run mini apps or frames." + }; + view! { +

{note}

+ {(!cast.spam).then(|| view! { })} + } + .into_any() + } else { + view! { +
+ + + + {body_payload.quotes.iter().map(|quote| match "e.cast { + Some(q) => view! { + + }.into_any(), + None => view! { "↳ quoted cast unavailable" }.into_any(), + }).collect_view()} + } + .into_any() + } + }; view! {

"You deleted this cast."

@@ -334,30 +364,8 @@ fn MainCast(mut cast: Cast, notes: Notes, payload: Arc) -> impl Int - {if crate::miniapps::hides(&cast) { - let note = if cast.spam { - "Post hidden: Allthing leaves out posts with links to vercel.app apps, gig-bot, DEGEN reward or airdrop bait, and DEGEN staking promotions." - } else { - "Mini app post hidden: Allthing does not run mini apps or frames." - }; - view! { -

{note}

- {(!cast.spam).then(|| view! { })} - } - .into_any() - } else { - view! {
}.into_any() - }} - - - + {body} - {payload.quotes.iter().map(|quote| match "e.cast { - Some(q) => view! { - - }.into_any(), - None => view! { "↳ quoted cast unavailable" }.into_any(), - }).collect_view()}

A cold-load diagnostic fixture

' })); await page.route("**/__perfdiag.css?*", (route) => route.fulfill({ contentType: "text/css", body: "body{margin:0}img{display:block}" })); await page.route("**/__perfdiag.png?*", (route) => route.fulfill({ contentType: "image/png", body: readFileSync("web/pfp.png") })); - await page.route("**/api/v1/home?*", (route) => route.fulfill({ json: { pool: [] }, headers: { "x-allthing-cache": "fresh", "cf-cache-status": "HIT", "cf-ray": "fixture-BEG", "server-timing": 'fresh;dur=3;desc="https://user:private@example.com/?header-secret"' } })); + await page.route("**/api/v1/home?*", (route) => route.fulfill({ json: { pool: [] }, headers: { "x-allthing-cache": "fresh", "cf-cache-status": "HIT", "cf-ray": "fixture-BEG", "server-timing": 'fresh;dur=3;desc="https://user:private@example.com/?header-secret;dur=999,private", backend;dur=4' } })); await page.goto("/__perfdiag?document-secret"); await page.evaluate(async () => { await (await fetch("/api/v1/home?api-secret")).json(); }); await expect.poll(() => page.evaluate(() => (window as any).__allthingPerfDiagnostics.lcp?.element?.tag), { timeout: 5000 }).toBe("IMG"); @@ -26,7 +26,7 @@ test("cold-load diagnostics retain LCP, resource phases and cache evidence witho expect(result.lcpResource?.url).toMatch(/\/__perfdiag\.png$/); expect(result.navigation.response).toBeGreaterThan(0); expect(result.resources.some((resource) => resource.url.endsWith("/api/v1/home") && resource.end >= resource.start)).toBe(true); - expect(result.responses.find((response) => response.url.endsWith("/api/v1/home"))).toMatchObject({ cache: "fresh", cfCache: "HIT", colo: "BEG", serverTiming: [{ name: "fresh", duration: 3 }] }); + expect(result.responses.find((response) => response.url.endsWith("/api/v1/home"))).toMatchObject({ cache: "fresh", cfCache: "HIT", colo: "BEG", serverTiming: [{ name: "fresh", duration: 3 }, { name: "backend", duration: 4 }] }); expect(result.longtasks.some((task: { duration: number }) => task.duration >= 50)).toBe(true); const serialized = JSON.stringify(result); expect(serialized).not.toMatch(/secret|password|private|reader:/); From 75249aa31317cc867c0680131194fe78b95558a6 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 16:43:44 +0200 Subject: [PATCH 06/31] fix(feed): exclude future casts before ranking every range --- CHANGELOG.md | 1 + crates/allthing-core/src/index.rs | 15 ++++-- crates/allthing-core/src/latest.rs | 16 ++++-- crates/allthing-core/src/ranking.rs | 19 ++++--- crates/allthing-data/src/indexer.rs | 2 +- crates/allthing-data/src/pages.rs | 72 +++++++++++++++++++++++-- crates/allthing-web/src/pages/home.rs | 25 +++++---- crates/allthing-worker/src/index.rs | 5 +- docs/ARCHITECTURE.md | 2 +- docs/BUDGET.md | 2 + e2e/early-paint.fixture.spec.ts | 16 ++++++ e2e/feed-session-ranges.fixture.spec.ts | 48 ++++++++++++----- web/paint.js | 6 +-- 13 files changed, 184 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 491762da..03995299 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch ### Fixed +- Future-dated casts cannot outrank the present in For you or Following, including All time and early paint. Cached newest-cast payloads and index rankings exclude future timestamps before selecting their visible rows. - A directly opened mini app post follows Show mini app casts immediately in both directions, without a reload or refetch. Hiding it removes its body and embedded content while retaining its Open in Farcaster link; ordinary posts keep their content. - Short time ranges include newly posted casts even while Hypersnap's trending list lags behind. Every sort keeps the chosen range, and the end-of-range note appears below the list without moving cards down. diff --git a/crates/allthing-core/src/index.rs b/crates/allthing-core/src/index.rs index eee05e34..7fdec1fb 100644 --- a/crates/allthing-core/src/index.rs +++ b/crates/allthing-core/src/index.rs @@ -166,7 +166,7 @@ pub fn candidates(raw: &[RawCast], metas: &[RankingMeta], now: i64) -> Vec + RECAST_WEIGHT * count(reactions.and_then(|x| x.recasts_count)) + count(r.replies.as_ref().and_then(|x| x.count)); let ts = r.timestamp.as_deref().and_then(parse_rfc3339).unwrap_or(0); - points >= floor(metas, ts, now).min(NOTABLE_POINTS) + TrendingWindow::All.holds(ts, now) && points >= floor(metas, ts, now).min(NOTABLE_POINTS) }) .map(normalize::cast) .collect() @@ -179,7 +179,9 @@ pub fn worth_indexing(casts: &[Cast], metas: &[RankingMeta], now: i64) -> Vec= floor(metas, c.ts, now)) + .filter(|c| { + !c.is_reply() && !c.spam && TrendingWindow::All.holds(c.ts, now) && points(c) >= floor(metas, c.ts, now) + }) .filter(|c| seen.insert(c.hash.as_str())) .map(|c| Entry(c.hash.clone(), c.ts, points(c))) .collect() @@ -489,7 +491,8 @@ mod tests { {"hash":"0x02","timestamp":"2026-10-01T00:00:00Z","reactions":{"likes_count":5}}, {"hash":"0x03","parent_hash":"0x01","timestamp":"2026-10-01T00:00:00Z","reactions":{"likes_count":900}}, {"hash":"0x04","parent_hash":"","timestamp":"2026-10-01T00:00:00Z","reactions":{"likes_count":260}}, - {"hash":"0x05","timestamp":"2026-10-01T00:00:00Z","reactions":{"likes_count":100}} + {"hash":"0x05","timestamp":"2026-10-01T00:00:00Z","reactions":{"likes_count":100}}, + {"hash":"0xfuture","timestamp":"2061-09-12T00:03:58Z","reactions":{"likes_count":1000000}} ]"#, ) .unwrap(); @@ -501,6 +504,12 @@ mod tests { assert_eq!(hashes(candidates(&raw, &metas(400, 400, 600), now)), ["0x04"]); } + #[test] + fn future_dated_casts_are_not_indexed_even_when_their_points_would_rank() { + let casts = vec![cast("0xfuture", 1, NOW + 1, 1_000_000), cast("0xnow", 1, NOW, 30)]; + assert_eq!(worth_indexing(&casts, &[], NOW), [Entry("0xnow".into(), NOW, 30)]); + } + #[test] fn notable_authors_come_best_first_once_each() { let casts = diff --git a/crates/allthing-core/src/latest.rs b/crates/allthing-core/src/latest.rs index 8a162b30..1d41da6e 100644 --- a/crates/allthing-core/src/latest.rs +++ b/crates/allthing-core/src/latest.rs @@ -154,13 +154,15 @@ pub fn to_hydrate(added: &[Added], listed: &[Cast], removed: &[String], limit: u } /// The newest `keep` casts of `listed` and `fresh` (newly read, so they -/// replace listed copies), without `removed` ones. -pub fn newest(listed: Vec, fresh: Vec, removed: &[String], keep: usize) -> Vec { +/// replace listed copies), without `removed` or future-dated ones. Filter before +/// truncation so an invalid future timestamp cannot take a real cast's slot. +pub fn newest(listed: Vec, fresh: Vec, removed: &[String], keep: usize, now: i64) -> Vec { let fresh_hashes: HashSet = fresh.iter().map(|c| c.hash.clone()).collect(); let mut all: Vec = fresh .into_iter() .chain(listed.into_iter().filter(|c| !fresh_hashes.contains(&c.hash))) .filter(|c| !removed.contains(&c.hash)) + .filter(|c| TrendingWindow::All.holds(c.ts, now)) .collect(); all.sort_by(|a, b| b.ts.cmp(&a.ts).then_with(|| a.hash.cmp(&b.hash))); all.truncate(keep); @@ -342,8 +344,16 @@ mod tests { fn keeps_the_newest_casts_with_fresh_counts_and_without_removed_ones() { let listed = vec![cast("0xa", 30, 1), cast("0xb", 20, 1), cast("0xc", 10, 1)]; let fresh = vec![cast("0xd", 40, 0), cast("0xb", 20, 7)]; - let kept = newest(listed, fresh, &["0xa".into()], 3); + let kept = newest(listed, fresh, &["0xa".into()], 3, 40); let summary: Vec<(&str, u64)> = kept.iter().map(|c| (c.hash.as_str(), c.likes)).collect(); assert_eq!(summary, [("0xd", 0), ("0xb", 7), ("0xc", 1)]); } + + #[test] + fn future_dated_fresh_and_cached_casts_cannot_take_a_newest_slot() { + let listed = vec![cast("0xoldfuture", 2_893_718_638, 999), cast("0xold", 20, 1)]; + let fresh = vec![cast("0xnewfuture", 41, 999), cast("0xnow", 40, 1)]; + let hashes: Vec<_> = newest(listed, fresh, &[], 2, 40).into_iter().map(|c| c.hash).collect(); + assert_eq!(hashes, ["0xnow", "0xold"]); + } } diff --git a/crates/allthing-core/src/ranking.rs b/crates/allthing-core/src/ranking.rs index 1570330b..e1365e14 100644 --- a/crates/allthing-core/src/ranking.rs +++ b/crates/allthing-core/src/ranking.rs @@ -189,10 +189,10 @@ impl TrendingWindow { /// Whether a cast posted at `ts` is inside the window at `now` (both in /// seconds since the Unix epoch, which has no time zone). The window /// starts just after `now − span`: a cast exactly that old is out, and - /// one a second newer is in. A cast newer than `now`, from a clock a - /// little ahead, is in. + /// one a second newer is in. Future-dated casts are out in every range, + /// including all time; a clock ahead becomes eligible when `now` catches up. pub fn holds(self, ts: i64, now: i64) -> bool { - self.span_secs().is_none_or(|span| ts > now - span) + ts <= now && self.span_secs().is_none_or(|span| ts > now - span) } /// The window in words, for a note under the list. @@ -498,6 +498,7 @@ mod tests { (TrendingWindow::Day, 86_400), (TrendingWindow::Week, 604_800), (TrendingWindow::Month, 2_592_000), + (TrendingWindow::Year, 31_536_000), ] { assert_eq!(window.span_secs(), Some(span), "{window:?}"); assert!(!window.holds(now - span, now), "{window:?} exact boundary is out"); @@ -505,12 +506,18 @@ mod tests { assert!(!window.holds(now - span - 1, now), "{window:?} one second outside is out"); assert!(window.holds(now, now), "{window:?} now is in"); } - // A cast from a clock a little ahead is in, not dropped. - assert!(TrendingWindow::Hour.holds(now + 5, now)); + // No unbounded clock-skew allowance: even a slightly early cast waits + // until its timestamp is reached, rather than outranking the present. + for window in TrendingWindow::ALL { + for future in [now + 1, now + 5, 2_893_718_638, i64::MAX] { + assert!(!window.holds(future, now), "{window:?} future {future} is out"); + } + assert!(window.holds(now + 5, now + 5), "{window:?} eligible when the clock catches up"); + } } #[test] - fn a_window_for_all_time_holds_every_cast() { + fn a_window_for_all_time_has_no_lower_bound_but_excludes_the_future() { assert_eq!(TrendingWindow::All.span_secs(), None); assert!(TrendingWindow::All.holds(0, 1_792_000_000)); assert!(TrendingWindow::All.holds(i64::MIN / 2, 1_792_000_000)); diff --git a/crates/allthing-data/src/indexer.rs b/crates/allthing-data/src/indexer.rs index 957b3494..2d88b895 100644 --- a/crates/allthing-data/src/indexer.rs +++ b/crates/allthing-data/src/indexer.rs @@ -207,7 +207,7 @@ pub(crate) mod tests { let casts = self.casts.borrow(); let mut inside: Vec = casts .iter() - .filter(|(_, (ts, _))| *ts >= cutoff) + .filter(|(_, (ts, _))| *ts >= cutoff && TrendingWindow::All.holds(*ts, (now_ms / 1000.0) as i64)) .map(|(h, (ts, p))| Entry(h.clone(), *ts, *p)) .collect(); let total = inside.len() as u64; diff --git a/crates/allthing-data/src/pages.rs b/crates/allthing-data/src/pages.rs index e9149c98..9cadbf67 100644 --- a/crates/allthing-data/src/pages.rs +++ b/crates/allthing-data/src/pages.rs @@ -315,7 +315,7 @@ fn now_secs(inv: &Invocation) -> i64 { (inv.now() / 1000.0) as i64 } -/// The casts posted within `window` at `now`; all of them for all time. +/// The casts posted within `window` at `now`; all time still excludes the future. fn within(window: TrendingWindow, now: i64, casts: Vec) -> Vec { casts.into_iter().filter(|cast| window.holds(cast.ts, now)).collect() } @@ -406,6 +406,7 @@ pub async fn following( let first = cursor.is_none(); let mut notes = carried(previous.as_deref().map(Vec::as_slice)); let known_links = std::mem::take(&mut notes.links); + let now = now_secs(&inv); let top_level = |raw: &[RawCast]| raw.iter().map(normalize::cast).filter(|c| !c.is_reply()).collect::>(); let (mut raw, mut next) = hypersnap::following_feed(&inv, fid, cursor.as_deref()).await.map_err(Failure::upstream)?; @@ -417,6 +418,9 @@ pub async fn following( raw.extend(more); next = after; } + // Keep the existing page-read decision: validation must not fetch another + // upstream page merely to replace rows with invalid future timestamps. + let theirs = within(TrendingWindow::All, now, theirs); let pool = drop_hidden(&inv, theirs, &mut notes, &known_links, true).await; let quoted = annotate_listing(&inv, &mut notes, &pool, ORIGIN_AUTHORS, &known_links).await; notes.keep_users(read_cards(&raw, quoted), listed_accounts(&pool, ¬es.quotes)); @@ -503,7 +507,16 @@ pub async fn latest(inv: Rc, previous: Option>>) -> Resul && warm.as_ref().is_none_or(|p| stored.built > built_at(p)) { if inv.now() - stored.built < SNAPSHOT_SERVE_MS { - let body = stored.body.into_bytes(); + let mut payload: LatestPayload = serde_json::from_str(&stored.body) + .map_err(|e| Failure::internal(&format!("invalid newest-casts snapshot: {e}")))?; + let before = payload.pool.len(); + payload.pool.retain(|cast| TrendingWindow::All.holds(cast.ts, now_secs(&inv))); + // Preserve the exact stored bytes on the common unchanged path. + let body = if payload.pool.len() == before { + stored.body.into_bytes() + } else { + serde_json::to_vec(&payload).map_err(|e| Failure::internal(&e.to_string()))? + }; return Ok(Built { body, status: 200, policy: api::LATEST_CACHE, fetched_at: Some(stored.built) }); } warm = serde_json::from_str(&stored.body).ok(); @@ -595,7 +608,7 @@ async fn build_latest(inv: &Invocation, warm: Option) -> Result LocalBoxFuture<'static, Result> { let url = request.url.clone(); self.requests.borrow_mut().push(url.clone()); - let body = if url.contains("/feed/trending?") { + let body = if url.contains("/feed/trending?") || url.contains("/feed/following?") { let casts: Vec<_> = self .casts .iter() @@ -2424,6 +2469,8 @@ mod indexed_home_tests { ("0xa2", "2026-10-14T15:46:40Z"), ("0xa3", "2026-10-14T12:46:40Z"), ("0xa4", "2026-10-11T17:46:40Z"), + ("0xf1", "2026-10-14T17:46:41Z"), + ("0xf2", "2061-09-12T00:03:58Z"), ], requests: RefCell::new(Vec::new()), }); @@ -2443,6 +2490,23 @@ mod indexed_home_tests { assert!(!asked.iter().any(|url| url.contains("time_window=12h")), "{asked:?}"); } + #[test] + fn following_payloads_exclude_future_casts_without_changing_page_reads() { + let host = Rc::new(Trending { + casts: vec![ + ("0xpresent", "2026-10-14T17:46:40Z"), + ("0xfuture", "2026-10-14T17:46:41Z"), + ("0xfar", "2061-09-12T00:03:58Z"), + ], + requests: RefCell::new(Vec::new()), + }); + let inv = Rc::new(Invocation::new(host.clone(), 45)); + let built = following(inv, 7, Some("later".into()), None).now_or_never().unwrap().unwrap(); + let payload: FollowingPayload = serde_json::from_slice(&built.body).unwrap(); + assert_eq!(payload.pool.iter().map(|cast| cast.hash.as_str()).collect::>(), ["0xpresent"]); + assert_eq!(host.requests.borrow().iter().filter(|url| url.contains("/feed/following?")).count(), 1); + } + #[test] fn the_first_page_carries_the_polls_counts_once_someone_has_voted() { let counts = Counts { yes: 3, no: 1 }; diff --git a/crates/allthing-web/src/pages/home.rs b/crates/allthing-web/src/pages/home.rs index 10350970..23db731e 100644 --- a/crates/allthing-web/src/pages/home.rs +++ b/crates/allthing-web/src/pages/home.rs @@ -383,23 +383,26 @@ fn Trending(sort: Memo, listed: ReadSignal, range: Memo) let mut leanings = leaning.for_list(sorted_by, (order, filter)); // For you: the casts of whom the reader follows lifted. leanings.followed = followed.get_value(); - let mut all = sorted_for(&pool, order, &leanings); + // Cached out-of-range or future casts must not inflate + // span_days and distort the remaining casts' leaning weights. + let now = now_secs(); + let within = |casts: &[Cast]| -> Vec { + casts.iter().filter(|cast| shown.holds(cast.ts, now)).cloned().collect() + }; + let mut all = sorted_for(&within(&pool), order, &leanings); more.with(|pages| { for page in pages { all.extend( - sorted_for(&page.casts, order, &leanings) + sorted_for(&within(&page.casts), order, &leanings) .into_iter() .filter(|c| !first_hashes.contains(&c.hash)), ); } }); - let all = match filter { + match filter { Some(fid) => from_client(all, ¬es.get(), fid), None => all, - }; - // A copy from the edge, or the app's own, can be older than - // its window: what has aged out since is left out here too. - all.into_iter().filter(|cast| shown.holds(cast.ts, now_secs())).collect() + } }); let chip_notes = Arc::new(payload.notes.clone()); let in_window: Vec = @@ -466,7 +469,8 @@ fn Following(sort: Memo, listed: ReadSignal, range: Memo) } match result { Ok(page) => { - if let Some(newest) = page.data.pool.iter().map(|c| c.ts).max() { + let now = now_secs(); + if let Some(newest) = page.data.pool.iter().filter(|c| c.ts <= now).map(|c| c.ts).max() { tail.set(Some(newest)); } let mut known: std::collections::HashSet = more @@ -514,7 +518,10 @@ fn Following(sort: Memo, listed: ReadSignal, range: Memo) crate::followed::remember(fid, &payload); } next.set(payload.next.clone()); - tail.set(payload.pool.iter().map(|c| c.ts).max()); + // Future dates cannot establish that the source page is already + // older than the window; an invalid-only page behaves like an empty one. + let now = now_secs(); + tail.set(payload.pool.iter().filter(|c| c.ts <= now).map(|c| c.ts).max()); let first_notes = payload.notes.clone(); let notes = Memo::new(move |_| { let mut notes = first_notes.clone(); diff --git a/crates/allthing-worker/src/index.rs b/crates/allthing-worker/src/index.rs index 9ebceddb..b393a6f7 100644 --- a/crates/allthing-worker/src/index.rs +++ b/crates/allthing-worker/src/index.rs @@ -49,9 +49,10 @@ const STORE: &str = "INSERT INTO casts (hash, ts, points) \ /// Rank span ?1 (casts from ?2 on, Unix seconds) as of ?3 (Unix ms): its top /// ?4 casts, how many it has, its oldest, and its floor once full. const RERANK: &str = "WITH top AS (\ - SELECT hash, ts, points FROM casts WHERE ts >= ?2 ORDER BY points DESC, ts DESC LIMIT ?4) \ + SELECT hash, ts, points FROM casts WHERE ts >= ?2 AND ts <= CAST(?3 / 1000 AS INTEGER) ORDER BY points DESC, ts DESC LIMIT ?4) \ REPLACE INTO rankings (name, built, total, oldest, floor, body) \ - SELECT ?1, ?3, (SELECT COUNT(*) FROM casts WHERE ts >= ?2), (SELECT MIN(ts) FROM casts WHERE ts >= ?2), \ + SELECT ?1, ?3, (SELECT COUNT(*) FROM casts WHERE ts >= ?2 AND ts <= CAST(?3 / 1000 AS INTEGER)), \ + (SELECT MIN(ts) FROM casts WHERE ts >= ?2 AND ts <= CAST(?3 / 1000 AS INTEGER)), \ CASE WHEN COUNT(*) >= ?4 THEN MIN(points) ELSE 0 END, json_group_array(json_array(hash, ts, points)) \ FROM top"; diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index a92984fa..3bf68a59 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -157,7 +157,7 @@ Hypersnap ranks trending casts over 7 days at most, and its search ignores dates - **Storage.** `casts` holds each kept cast's hash, time and points; storing it again updates its points, and writes nothing if they haven't changed. `rankings` holds each span's top 1,000 casts as one JSON row, recomputed inside D1 by one statement, so the Worker never reads more than a page of casts. A ranking is due again a minute per 50 indexed casts after it was computed, between 5 minutes and 6 hours. `state` holds where each feed is, and the day's D1 usage. - **Limits.** The indexer estimates its D1 rows read and written and stops reading for the day at 50,000 rows written or 2,000,000 read, half of the free plan's 100,000 and 5,000,000 or less, leaving the rest to the front page. See [BUDGET.md](BUDGET.md#9-the-index-cron-and-d1). - **Reading.** `/api/v1/home?window=30d|365d|all` reads the span's ranking row, then the page's 100 casts in one bulk `casts?casts=…` call, so counts, text and media are fresh; deleted casts drop out, spam is filtered again and mini apps are marked. The payload's `index` (`IndexCoverage`) says how many casts the span was ranked from and the oldest one's date, and the page shows it under the time filter. Until a span has a ranking (a new index, or D1 not answering), the payload is the past week's trending pool without `index`, and the page says so. The static copy has no index: its menu leaves these ranges out. -- **Time windows.** A trending window holds only the casts posted within it, judged by each cast's own time against the Worker's clock, before the page is cut (`TrendingWindow::holds`, the same edges in the browser, which drops what has aged out of a copy it was served). Hypersnap's `time_window` has 1 hour, 6 hours, 24 hours and 7 days; it answers 12 hours with its 24-hour list, which is cut to 12 hours. A page can hold fewer casts than a full batch, when the window holds fewer: the list then ends, and the page says so ("Only 3 casts in the past 12 hours.") instead of padding it with older casts. A copy is kept no longer than its window (`api::home_cache`). +- **Time windows.** A trending window holds only the casts posted within it, judged by each cast's own time against the Worker's clock, before the page is cut (`TrendingWindow::holds`, the same edges in the browser and early paint). The lower edge is exclusive and the present is inclusive: `now - span < ts <= now`. All time has no lower edge, but still excludes future timestamps. A cast from a clock ahead waits until the current time reaches it. Following and newest-cast payloads, including stored snapshots, also exclude the future, and index rankings cannot let future rows fill their slots. These checks use existing reads; the stored newest-casts fast path parses its payload to validate timestamps and serializes again only when rows are removed. Hypersnap's `time_window` has 1 hour, 6 hours, 24 hours and 7 days; it answers 12 hours with its 24-hour list, which is cut to 12 hours. A page can hold fewer casts than a full batch, when the window holds fewer: the list then ends, and the page says so ("Only 3 casts in the past 12 hours.") instead of padding it with older casts. A copy is kept no longer than its window (`api::home_cache`). - **Coverage** grows as the feeds are read back: Past month and Past year fill within hours, and All time keeps deepening for days as the queued authors' histories are read. The ranking reflects what has been indexed, which the note under the filter states. ## Daily active accounts diff --git a/docs/BUDGET.md b/docs/BUDGET.md index 82bb7494..6f781df9 100644 --- a/docs/BUDGET.md +++ b/docs/BUDGET.md @@ -71,6 +71,8 @@ Images and videos never touch the Worker, except readers' own attachments, which The front page fills the space near the end of the list even when filtering leaves a batch short or empty. It can request offsets 100 through 900, at most nine additional payloads (1,000 source casts including the first page). Each payload remains a separate cached, guarded invocation with the same 45-subrequest budget. Failed pages keep their 2, 4 and 8 second retry delays. Deep scrolling or short filtered batches can therefore cost up to ten home requests per visit; the typical capacity estimate below does not describe that worst case. +Future timestamp checks use the existing payloads and add no cache, D1 or upstream reads. Following keeps its existing decision about reading a second source page before invalid dates are removed. Serving the stored newest-casts snapshot now parses its timestamps; unchanged snapshots retain their exact bytes and only filtered snapshots are serialized again. The invocation still has the same 45-subrequest limit. + **Prefetching** ([PERFORMANCE.md](PERFORMANCE.md)) spends Worker requests ahead of clicks, within caps: - hover or touch on a card: one `/api/v1/cast` request, deduplicated; - a link to a post or a channel pressed, touched, focused, or with a mouse resting on it for 100 ms: one request for the page it opens (`/api/v1/cast` or `/api/v1/channel`), deduplicated and reused for 5 minutes; a press asks for the page's own request a moment early, and only a link rested on or focused but not followed costs one more; diff --git a/e2e/early-paint.fixture.spec.ts b/e2e/early-paint.fixture.spec.ts index 96a782e3..2b373e0b 100644 --- a/e2e/early-paint.fixture.spec.ts +++ b/e2e/early-paint.fixture.spec.ts @@ -205,6 +205,22 @@ async function moduleIn(page: Page, held: Awaited>) { .toBe(true); } +test("future dates never appear in early paint or after the app takes over", async ({ page }) => { + const held = await hold(page); + const future = { ...favorite, hash: hex(900), ts: 2_893_718_638, likes: 1_000_000, embeds: [] }; + await serve(page, { ...payload, pool: [future, ...pool] }); + await favorites(page); + await page.goto("/"); + const boot = page.locator("#boot"); + await expect.poll(() => boot.locator(".cast-card").evaluateAll((cards) => cards.map((card) => card.getAttribute("data-hash")))).toEqual(painted); + await expect(boot.locator(`[data-hash="${future.hash}"]`)).toHaveCount(0); + await moduleIn(page, held); + held.js("continue"); + await expect(boot).toHaveCount(0); + await expect(page.locator("#app .cast-card").first()).toBeVisible(); + await expect(page.locator(`#app [data-hash="${future.hash}"]`)).toHaveCount(0); +}); + for (const width of [1280, 390]) { test(`the front page's first cards come before the app, as it draws them, and its own take their places at width ${width}`, async ({ page }, info) => { await page.setViewportSize({ width, height: 844 }); diff --git a/e2e/feed-session-ranges.fixture.spec.ts b/e2e/feed-session-ranges.fixture.spec.ts index c4ff0d4c..de91c4c6 100644 --- a/e2e/feed-session-ranges.fixture.spec.ts +++ b/e2e/feed-session-ranges.fixture.spec.ts @@ -16,6 +16,9 @@ const cast = (n: number, age: number, likes = 0) => ({ }); const pool = [1800, 3 * 3600, 9 * 3600, 18 * 3600, 2 * 86400, 15 * 86400, 100 * 86400, 400 * 86400] .map((age, i) => cast(i + 1, age, i * 10)); +// Upstreams and old cached payloads can contain invalid future dates. They +// must never dominate Hot/Top/New, even in All time or Following. +pool.push(cast(9, -86400, 1_000_000), { ...cast(10, 0, 1_000_000), ts: 2_893_718_638 }); const order = (page: Page) => page.locator("#app .cast-list .cast-card:not(.skeleton)") .evaluateAll((cards) => cards.map((card) => card.querySelector(".cast-text")?.textContent?.trim())); @@ -54,7 +57,7 @@ for (const width of [1280, 390]) { const selector = page.getByRole("combobox", { name: "Time range" }); await expect(selector).toBeVisible(); await expect(selector).toHaveValue(range); - const expected = pool.filter((c) => now - c.ts < span).map((c) => c.text); + const expected = pool.filter((c) => c.ts <= now && now - c.ts < span).map((c) => c.text); await expect.poll(async () => (await order(page)).toSorted()).toEqual(expected.toSorted()); if (sort === "new") expect(await order(page)).toEqual(expected); expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true); @@ -75,21 +78,40 @@ async function switchReader(page: Page, user: typeof me | null) { }, user); } -test("Following hot ranks within its window before applying favorites", async ({ page }) => { +for (const feed of ["For you", "Following"]) { + test(`${feed} hot ranks within its window before applying favorites`, async ({ page }) => { + await signIn(page, me); + await serve(page); + await page.addInitScript(() => localStorage.setItem("allthing.favorites", JSON.stringify([{ fid: 1, username: "author1" }]))); + const quietFavorite = cast(1, 50 * 60); + const busyRecent = cast(2, 10 * 60, 100); + const outside = cast(3, 400 * 86400); + const future = { ...cast(4, 0), ts: 2_893_718_638 }; + for (const path of ["home", "following"]) await page.route(`**/api/v1/${path}**`, (route) => route.fulfill({ + json: { pool: [future, outside, quietFavorite, busyRecent], notes: {}, meta }, headers: privateHeaders, + })); + await page.goto(`/?t=hour${feed === "Following" ? "&feed=following" : ""}`); + // In an hour's pool, 25x a quiet cast's weight cannot beat 100 points + // posted more recently. Including an old or future cast before ranking + // scales that lift by its entire span, sending the favorite to the top. + await expect.poll(() => order(page)).toEqual([busyRecent.text, quietFavorite.text]); + }); +} + +test("Following crosses a cached future-only page to reach the present", async ({ page }) => { await signIn(page, me); await serve(page); - await page.addInitScript(() => localStorage.setItem("allthing.favorites", JSON.stringify([{ fid: 1, username: "author1" }]))); - const quietFavorite = cast(1, 50 * 60); - const busyRecent = cast(2, 10 * 60, 100); - const outside = cast(3, 400 * 86400); - await page.route("**/api/v1/following**", (route) => route.fulfill({ - json: { pool: [outside, quietFavorite, busyRecent], notes: {}, meta }, headers: privateHeaders, - })); + const asked: number[] = []; + const future = { ...cast(40, 0), ts: 2_893_718_638 }; + const present = cast(41, 60); + await page.route("**/api/v1/following**", (route) => { + const cursor = Number(new URL(route.request().url()).searchParams.get("cursor") || 0); + asked.push(cursor); + return route.fulfill({ json: { pool: cursor === 0 ? [future] : [present], next: cursor === 0 ? "1" : null, notes: {}, meta }, headers: privateHeaders }); + }); await page.goto("/?feed=following&t=hour"); - // In an hour's pool, 25x a quiet cast's weight cannot beat 100 points - // posted more recently. Including the old cast before ranking scales - // that lift by 400 days, incorrectly sending the favorite to the top. - await expect.poll(() => order(page)).toEqual([busyRecent.text, quietFavorite.text]); + await expect.poll(() => order(page)).toEqual([present.text]); + expect(asked).toEqual([0, 1]); }); test("Following crosses empty pages, stops at an old tail, and resumes when the range widens", async ({ page }) => { diff --git a/web/paint.js b/web/paint.js index 7f7475d4..9e4c0ed6 100644 --- a/web/paint.js +++ b/web/paint.js @@ -106,9 +106,9 @@ async function paint(payload, { sort, range, reader }) { reading = reader !== null; const notes = payload.notes || {}; const lean = leanings(reader); - // A cast older than its window is left out, as the app leaves it out of a copy from the edge. - const now = Date.now() / 1000; - const inWindow = (cast) => cast.ts > now - SPANS[range]; + // The same inclusive present and exclusive lower edge as TrendingWindow::holds. + const now = Math.floor(Date.now() / 1000); + const inWindow = (cast) => cast.ts <= now && cast.ts > now - SPANS[range]; // Mini app casts only for a reader who shows them (miniapps.rs). const apps = showsMiniApps(); const casts = sorted(payload.pool.filter((c) => !c.parent_hash && inWindow(c) && (apps || !c.mini_app)), sort, lean).slice(0, CARDS); From 344260248b7589388b4a3b61b450a0466b226a6d Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 16:45:45 +0200 Subject: [PATCH 07/31] test(profile): restore seen rows when checking hover leanings --- e2e/hover-card-leanings.fixture.spec.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/e2e/hover-card-leanings.fixture.spec.ts b/e2e/hover-card-leanings.fixture.spec.ts index d8c661c1..44a2c892 100644 --- a/e2e/hover-card-leanings.fixture.spec.ts +++ b/e2e/hover-card-leanings.fixture.spec.ts @@ -154,6 +154,7 @@ for (const phone of [false, true]) { await serve(page); await page.goto("/"); await appCame(page); + await expect.poll(() => order(page)).toEqual(casts.map((c) => c.hash)); const before = await order(page); expect(before).toEqual(casts.map((c) => c.hash)); @@ -195,7 +196,13 @@ for (const phone of [false, true]) { // The next load of the feed takes the new order: alice's cast sinks. await page.goto("/"); await appCame(page); - await expect.poll(() => order(page)).toEqual([casts[1].hash, casts[2].hash, casts[0].hash]); + await expect.poll(async () => { + // Reading the open card and its screenshot can mark the feed seen. + // Restore its rows through the real control when this generation arrives. + const show = page.getByRole("button", { name: "Show seen posts", exact: true }); + if (await show.isVisible()) await show.click(); + return order(page); + }).toEqual([casts[1].hash, casts[2].hash, casts[0].hash]); // And pressing again takes it back. const again = await open(page, alice, phone); From 8e393a66be90ddca50c2ccbf37387885cb36ae44 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 16:49:39 +0200 Subject: [PATCH 08/31] docs: refresh the release screenshots --- README.md | 2 +- docs/screenshots/dau.webp | Bin 39206 -> 34462 bytes docs/screenshots/home.webp | Bin 60002 -> 71550 bytes docs/screenshots/profile.webp | Bin 36726 -> 31008 bytes 4 files changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e87c9c3c..bae3a773 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Allthing is an independent Farcaster client, written in Rust, that shows trendin **Live at [allthing.social](https://allthing.social).** -![The Allthing front page: trending Farcaster casts with their likes, recasts and replies, the app each one was posted from, and Allthing's poll](docs/screenshots/home.webp) +![Allthing's Following feed with For you and Following tabs, sorting and time ranges, Settings, the online count and Allthing's poll](docs/screenshots/home.webp)

A profile: bio, website, followers and following, join date, NS vote and wallet activity by chain diff --git a/docs/screenshots/dau.webp b/docs/screenshots/dau.webp index 5999348910ea3cdaf6959cd0274616b622b5128b..48840fd5678bf6f5d25e98c96be95e08fc39fdb6 100644 GIT binary patch literal 34462 zcmafaW0WXMw`AKqZJoAl+qP}nwvE%aZQHhO+s2%GzxQU|%%7=0S!-2Q=B|v$h`noN zDTs@RB!>V1s0s_nsmQV6Mf^R#bq2};q__h?1LhGYiW4Eo$Ir_{G)ItwgfzF=j54)N zwoE0v5o><`DfkxbjPw-!xUw;wc!`eBZ z`@{LY@?~2~TjeYCWB-lxx$-0Xj0=g2^&R+W`*QR7`}*7VtK_rg)pj(t7Wd$1o_F#m z`0MTm<>%+8XZz>L3#SL;d*O%m9o`T3IA_)O_{aB$@k8-(;LG*f_F?DZ$H9B;JMvrh z2mGD(IfsCE(zn5P;``$}_W9!H)#$Jxe^oui9pBvXcH$6)y?=SD7wcl7m1A%Dk*9w~ zLV1n64f{EJlq%ovw8CZ=LMa;+SZiHNL(@`Ff*HH3oYh9$45d7usP1I>Md5jz`$+g^ zrkn5(frT&HhRrsq$uAjbE}CH?>3{tAcH=<;B~JZZkpKg^TlgmV4)Wu zKk$Q^-vC2_Xy?SLMkx$GzfIUJrAkuM`ebssxIfetK|Bw9EM|fmu~f#bYewQ#DrQ@m z*esN&TJJ!tVwyM{UfZB~Q_b-XU9*1?`a3zisI;>8!Ep4e|4Nh}`W{|C}G_ zs~H((X!U+&H8dm`hXi5}dW_6(rK?QKji`%TivkuBvfn8X5elG>s~UAIv26Gh-9u%v z#7-jGW zIxf1v_pp!n(2eNc&E}3sdNQg28n!g!x`Sb8*XRk(R5)aT<`(A%bvZ-^h*|`w1f&{N z6(IrBB&HVMwJ8+5OXqfk%6I)jEkPZh9>0TVX+Y`5PgR+RCqNuwBwEC%GIt6C1Dn)>_>fjmz@85KLY`#Zz zb0z#Zd`)>1m=<{B+6YCztRV>wxrncU-PmoxsddjUBrkhS-uGD<=QNc)6ImZq4?=C( zENO5dk`0X3lB)0J*{_W2vOYTNvbwv%6gP#ag||PCY?YYX0sNA71`3Yf4_9)isdr~y z)~NRcKGOpSjm**4wfJ|SwO7kB91J>`xu^+@1z}~0H95G8x1158F#KvyAm1LqVrCv` zYf5b{Dz7uH8;eaG6elv@i`bBKr_NKid3_dP3fio`>-u+&K}aB^1TQH?(B65t+S>)+HiD$0Zf==^??3RbEPXdd$ZpEZyz@ne zchl%X7d~;E0E3r1!5{W)pf$D;bW=!d6*&AUT>=9M*c>AqY%6ToUpgkcU6m+eVWcio zM5cwTc2T~Wv?;}p|ELAVtIm4P(&`OG41p@&?OuhW6~usd{|-udyWdD_ug#|o%`deh zlW@740Mo+G^}I1%!Nohew(hzPoI?Yg`dG#$2syeLKo|i`_#Tw|P#SAnz@FUwY4PKT zW<_&`-T8EPD-;&H;Vxq!7Omm)TG;f_288nxPlVTqo4Wnu5XG$N?t0@e8EVO{$21%Z zh5LJT@0s$1K245H=H_wnw$2{OMuclzbza;=;ghnAseL8=I-1Th*7Ws~Ab<_Fj$u#3 zNXr~?m*qNDLC2xk4@Ge|tE=fj&uz`TznN7F``7mMhF@`kOIL%eHuC$$1o+ot7In-t zJyeFPID4z{7j;~bYrmx_jJw%j0NxSj`O9{jg^?p;YxFoeEV@Q31M_vlMjDhZ-Mv$# zg2mI^L9pz4)#GA~T!X^L$#Nc-<=uym$imPs+c^KB6vSS2-q5Wv= z&8OyrYe_o*fm%Ql{f5Q%if3vkb|)-097p6X$zcd^1kzLV@?y}NX{X!?_Dno)KY*u6 zm1fs>WFL|hJ8)Krd-SRfKlWCmw)eK?PTS}4g(Jj)S${WVDAWW}z#s_iW&()X0LAIF zoH27JdP&&;e%V`rCseB+gR!1fC2jIhrq0x`7<<^(%P_=Py8<{$ zHm@Jv>x`Mlj6Z)oF@c(|kg%h%bmj|ox1W-@?h^H^jknnHT(~4EW@z_fTm35*tw4u4 zm9w0&3VYt+8&@Fzgl3n&4uoIrJ8eUlN71O-e3s&$270f$Y z@WCxbhu?e9imcf2X!PFa%0unmK~g~J&;c1zVY74Yf|`Pw=UB41xz)-^X})sqvdJw8 zZWXorXaZFI*MRXS_I%OG9O#y;k56xASeHm?Pok3Uy==$aa;W0GpElMYS5Kj@v6DTj z(64w)B{j4FToiE)^!PsYEW_$JlL>ffTPr$MVByY8YU4ee{#&Q)z_HvK0!4GX&j$W< z1il%GknvrAZcUyT)I+lPX^7LlQ^y*w+y(tg=*5_DY_T=;VEZ|_%sBWg3OvmSS64`I z1-|H$fZjrNaTqeVr`4S50wnEk+`GRuFo$El^b+)E3wASYrT1qv`C z_A)Fkte+L{)I}$cmRH6swGC3DrA!&r3=KKn=8e+*jb7&pMkN6=BKXC7nr;rTb0#F7 z=u`zd7Q#zab0LovKnVl}>~98Q+MrWmv&}&a7cDkFJMspN<(A=U`V-`l-HSaairP(a zvG$p+)<4xf0nb=67FU3>C~(?q=F4B1Jk}-oH;HQ+-tlAEP}!@!b>446QFAFt^N~z# z3o1iYeHn#k*^PE@{B;d*VAL%bUe$YkQDIWpy3d6xLdnj%bv=+BYoSK2R}_#8^>357 z+W=S>b;_|vZ4dsCDP6sbofeT%oRkXQgk7=wpT}67MnBcdKkjeNR9+@T5;OVQ+A3G9)zc)4+>!gVFrdpeZE%-OSz%**}HT>dJy;sB) z(u(EPBV-_s>v#I&TOOZ$-&SQ{(>JRfxJOeG_Bo7uSX%mZPRGsQ$X@}$upZ=ayM9l4 zS`H*GTCv|iftnki;5borIgg;q-}dmU_p~4_!y3Lb z>a`S;`Kde~>#dk+! zJ1?>?bc2x+Mr&FOUm}vgp|nURl*dWbAR;rJnEvtiP@PvaL}5jUb;etTyprHzO#tgx zfU@4BCKJ8m^$W}24y?aQZ{Hi37qto^f+5CQw{|+%u6rVcqW=|BopLJogd{%cgn%A} z0)&wJ<^9hpJgF_GVpD$kGCPo~(?TW$kyB28(cA1;?-~7(2_*b|aavOgNinf9_uIP> zHF_Lx(Na(pw10fn<(>$--GdOU6peb4F1hl(D+;_d9o@ttP zw>knLobb{yASuPgCwiDo0~0YeJucnBEHLWpADqm!aNa6-s7;F~{xUBn(H`Ceag>H( zBbOZdqWagytgFrL_;Z5fcQDHE{%CI;HLU|BC>bx$dfv8;#IPRrUQka}*MrVkowAFB zC9$|%XamGEUU~!7vWG(TnDpownFK4}A^fTC?MU;`U)8DmtWCAxNzCsInaxQ3Ka$Bb zG&|Yn_G-B2M<7gNXW6_x`dod!32gq%8r{5F<9068&99hYhzn4q&2xqwFtMkVqTKma zkqhnW(2$$lfA)o9(t$EQKog0dR*#XzBIdRzpe689;fKA+@CGXL*Or)Xi#02BKviZzSUj)IN1K zkji;Y)*yG;=**y<%~>R-$ua94QknbxMd0;Cfv_JZ7tSa0c&r^tcx&%Jh6bDwj0pkJ zj<)Hk`#7)5;&d5X`U6-+1%XdJ&*)vLTsx3Veoh@vL}H(_s|``r4z=PvM3$^~n1=O5 z8?_Jq)KqaJX!!C?Q4xOE_2qQf8n!= zIN7)2vB>yW%2uJhMf1OG`kS{~6-cC@ZWt6%YQQA7Hfg$oB=B(;mo;#r9T8*fGP-z$>7HWwLqef5!JuZJ%Dl0Fg5Bi1n|F9&CyIgS*w(g)Z!f*9cl{ z2oL&SF8^Q6_6wL17_}sedJwz%H5rg{BcaGYv!2c({BL#RsI5-^525}kp8o9;{onTVzu{7?fVWnNCzl=~$i`8@ zUoWQW+GbuvCEFVD4?l&iKCInQ_-9e2eQ5kkn^#d!;%aJ@|2aeA$q=2sGl7viW=R^7 z(ZLpStpfw&ng3|kQ-m&F*;Mr|+&|PQVfiQ36LtH^0iR+%9C3~NR}b_mcmKV^2eUox zFl+5-R;Jd+&qFJk6s}Jal$_F_P!7Z7^s=V7y1jijYG7mh_{4xCj|}m4q_?rA|1y_y z(InpOxBt1|$Z~x@R!ZH9SbP`qlKT0opnUzVKAnjontaWgQsn#`MZMUt6Blz7+4-_s z=?6lq@!vXo+c7*V_it>zfw<&T0_$+@>9VlP?l^^x*5cZ;0u)w8zCEXP(-$^7muxiX z$63U@u9Q6ygMS@&-}S1r(eX8G5k_HE;K6RfXHoEB1H7xDP3}wc+4oz!QYrlJ`?6;4 z|C1uyO`#J19qd0E{y*TG4fOse<7hVR2LSl~X2!I)2qnUw&1y4_T~6|ieWEfD>k{Ie z>~ja7;;=;9we3iciNpx^e)SM3QelxM>Dc7o!!(*9k7DP!FD*v`|`m zs>{qru+1@QpB6%AL;{k_cyx1H>z0Czj?To3YW4DO51}|7!$CkoVX5{PH_`*sxDIRI z>A`1qjew4?1M{&nW44=&~SwzED&@{V0$}hRy1Z;ly+m#u-f#^SoIq}Z}5 z=&-}@gA{pe(u*{bofMfWX%0hKA!e#+YlCo@+@73Q%}(fMK4}LDX%=_k{My0$OZ5SM zsFRNHm`BB0m6O=1TK;Qoi$6Qw3OvG~(G?SAPr1r%O4dCg}P#CUkR^Im>a z!b|M$clm1pxjGRZu@Nxi!S8o*=@z5 zT0~fTVRDieW2P^Pe=J=&JEbWKQhc)o$#uo;o*M;}8cSCIoyLx)$m(VdiV+z{43G?aX!AlkFD^SVh4GJDk-0#83UUP#M1gd(2kWP(*<~ zn>m4;oi(^e0$5lQ&nXOt{Zn!aMB4booSBZDL1+7c8}$jTIWC9M;g8rGJ1Q|ShlT5G zBp4gh1)Yw0n+QJFpV%5721idq1m zgX}Y!I>75zMNW&0F=jH&A&UAMC@{68{r6n{s*lV=R(%IE%-N{IS?Y{_WIzzlW|6yN zSh8C7$pQDvi zRf^S?!j?Dmv$M95lgwU&u=wJ0m*v#f~`Mb;q7|TBEBD0vS2hW=Xm025$8rU?N z%*L!>`-tKh>_9?8Bm(Sb;6D#~H}9oleJ88`A6b-jtHBz%OXkH%;Wb{)?g z<=UktgF|)UpKcRPRG$IX_&gP7`zzb>)gmH#Zftw_GOiIRlY+`uY_86Q(PrGU{-iV5 z!idDVetXK_sDn6HAmRNM^wbj&iLlxOFy5zw)Hs81X zr5Xy~I^vX+h%&N5&dt$U>fArbde6!409?K~EMmShDore$d zJR^XgXKYvZU7E+5V3}YY#B)kDBMyk&k~GU7oZ1wy!s>Rb{Xqh!I=&q+7xA-unOD9J z9N-!=L1N!l=4Kp!otFkHzS=Vtn{3sNP5RFeHc3qGE2Py><=v15SA_AtO~b*#Niw?X z;3B?-Tp%n|59S$hM+CDpHUX?+3s$N^I?F0lei>c^B^;~>`G(PCCA8v%%l3c z<9VVsG8I@grrMuqc)?!CS1fd0KvV^&R0n=P2q{FbRq~#m_*A%8l?|b=byuSgz2S6J zHfN_-dKY0*lAJR&0>Mj==}pQ+wtgjpVCSTFBwHdyhQxj;^&mqbzNZidmh!T>S~E9o z$rDzRcwOpt^e_3xq|~K#NFU(>+y=}As6#;jMrI~InO)2&W|p?lXV-?_`?IDyOOn`3 zv8zXyHzLR`NL&_bSqX81z7s3>C=vxhxYdujR-6TW6%{q-Ya{_#QiYt!;SfsbtK(re z3+*IDwkgp&H?OH04$+D5aSZu-&%SoUTc*}mxjlr7y8Xs zx&*p?bmIx=DGGp!5R!CoiJr$v_aK%mC&ps>J2HA|Wl!{|a}aejZGsM~l~*?9OK+LB zKYZZNmCrF;BO?tN`&rWY+bbJmO(OozLOLuayw>_)X{Wp^)b99DFxj-R%@Zza35k)b zug5c%0JO}dR*C`9N{-8jD`$^hG@*_bkmPt48!AvHIKbcWv{`wnCpj4;~{IJX=z%3PU7ebK>RG9%-rde!h%s81m$c%l0inB>m z02GxbCVn3%Hdu%z4EGoy92M~7C8p9us~*Xl+c7+wnsawzRvc zstacFN*lxzzQZQ1vfKzt~ z3j`%4Lt$La)7>s3Pm9cRKrQi41klw|)6t4DpbaW*oq`Mu$jG@`x97ON<$%lh0bo?J z&wxqQv#4M81sGpgm54Isv2(W@=w-<&HHkL>Y_{NY!NqJMQ^U%ME7vWW%)4m5*~38B zU4W>?MWPr27eR zd3`%J+`CKn&?YNxx9>4Od594WqhQzD-z>~DdpRMY-L*cQVE<5H*ODfEp9?ThHdSka zFyCZac`R6rncG&&W2B@Xvmc>YE!Kts@Bl;h&# zs29-4YCKNjXdeDpFFxk>>48bhB6iYqvZhdbF=%(h8@-@h=LD)XWCKo9jC3gk-@H4d zMDe24sPcDViY{3M0-h2|AS2^({ca!g3x>DgzzlV)?tg-)))gfXO`NN29i1eS+}U5Q zF(cQmcG%gH`5LRoh^OQOe%>-|FHE9e@x3=>MwleHQmF-Wk1Mga8fegl!aF$A`Pl|M zzUfG;Y^HnW3x~19UkJUAX}skgj3h7?IKqL!dp6S<^S*x|pQtX?r4838wymL5iO6&= zQJHMJiB2`5mfh=SxsXlhmI|3-Q+7!2;dO0ymMSD$aS8V(^5bTma}>9GS%y6gTSxq< zZMWFJ6(wif<=9+K-Yy|$RyC{F-CIW^C0%+ZyBs~fN-+l+s8js<88jb*0-f6iC z!KyrWzXbnPL5C{ux0InUu>r(~UquA9B1|X}_fwc}aeZLG&26w+C0aWBgcLPfkR4f#+HXiLT21@Q92w%Y~J9_=%^K1UvM=YvwS2KOmHOD<8W-U6iV? zwdtVJ9CFeOIqw2F#R+mI2y&be;Do4@SN-vdJ@{Z8j&yxo^NDhT-XvJhuw1L$JY=0& zj4slu!`w$(wUS5L@N0?OrhuJb>(6&YVx>&0;c5F<3scTsU+26h5%X;>gR={Uf`0*P z8tgSB*H^vFo1I|-vz8XZ*eNZi?Mmy#bO#MQ^5;n*wZGcOUcm2SxZCisW7lc47?$s< zOMC(Fhk74ojW&-*<$-i!s4NpSwft@a_@1&0!$A*1I84VXYVsVT8` zPGa|K43ILYp9mTBVu9abKd2*1gz8h+far`NF+J^3P^A5?J5VJMBp8UvQ_FC*w|${y zpJWQmFB8S05A8L_rQ^6iY$W6@%pwXjNvhv~=tlnP!7)5*k+i7|nKyp*Q9blaowzm- zN@yU3!harivn}uAGcnU(9_p}4%YZr>;maMt@|WI6Oe%D3~pbfLwQPO|Eduv$b<_0cqoC;u3_)<$MAT#hgNMCGE4 zW@Cg4}ETOL#A}jJ#Y|ox1rkqkF3lk2#m_W?hpUC4-tcI~nHYS!T1T zGU6=-qf+r4J5A)oEc0#9Bdo{GtE!4pR{3w>EcV~aJ5jz8Iz?93R^eO{%Y9S>Z@iQY zsXg>6u;r1&97n)<)-Vj+oBbMx=_nma#+_8nRWTIQR75SeP$`-n_SQS-Y!|FKt8knK zC$VmCSx~fP%XB=U^FP+UcuL>0xX7-HRx%6anzgXTMyYJ?eHhy<{vdJ*D|0`B(}F5O zV*N%B$TOPay~t7qPBSLIbj5&KfIB5fW_fp?;~%4$j>57`k0qYrlEihegrjfk`)1Vn zD3d_$XWeSMcs(3<3@)KIY65XKDY{q<<)b_|F;%nQ;`g0=_svc8fsTgOoQvVJc<|9n=5JrEW)I(+~xPe$aAaFSSzAvnseTrlmo{B#;%7_MtNc9 z5trv^S`b^CuOxdkCJih0tZ;7U?jKzvh&(&UIv^cfs-75m$`;$6(TFWbTav@e5s-Yy zg86ENw2by_bs%KXCOxD@la?uBWvZ^NsAQtw? z4T;kpEM6ojtn^IW-0m%|YQ{|nOpy+r3&`N{Ty}WWWb|L;v^btPVCYe_9Abh(kTZHA zyszdGMVtK8u^0y-Kv_BunHa}JOr{^-#lY%#mLs`fXYXAB3`jQo06_RbM_}XU zI}MIauX}^FMG(6-HCb<^PYflI6exv~Bm=-O=xUa8xql*zo;?faH^FCadBDh=aYX&q8Ne&8` z|M2r4;mG?(#oD{RWTS`KlApCvt-SIRh)0eQnX?~%$YJ^f8skiMKX*Iw2XpH!K|TF^ zV&Y#3%U6MUp9-Zy@DZK@*?$SFNcjl|sI!;6E3={Uq1X|xPNDC($fOo{ zN%o@ImU2UL2?aJlc`En41BwXpYh~Ti8!?A6h;Oz@dmJEZME8pYFrDcg7d)_*%V2PG zm{N+qCtfWbo*Pu?>%;f&NCs6RAd?zfx^UOw80KfuZN=K%z}v+ zhtSi3&>$(ks6-f8J}M=*+>%IpFZj#eqlf`13_)s};?{AQGt?bDKd>i(>?V!5-UHZ* z!D-5e-6L<&U<^Z1!OkBw}zeXGhJer4+9Jp}5k&D0$on5Oug6qg^9_33kgB+Nqisxz90 zg|?+yYtlNA2s+tp4SL4MAM(LKikCVfYQ5R2IY_5==;U_*JAFoE`MUiuv2fvo<1H~> zT-;mJI%I-fLE7rQ>ridkWI%TJ%-@-3gPBf9IxWfPso1GXqZVFnVKQsXQS^QL+@#_` zR7U0bq`y655u>D2f3UE64CCcL9_7Gux|P1vsAryB!FpxYCM>~|{9WZxj6axR^_CX3 zZX3K?Mp8#k5Moq#@@7=y^0ZJKNV@p@@U3>SJKXM6$l}i$RrI~~9SMP4YB9z2nNrMcp`eZ9k#@gEP@Dr2^UgPmR zWeWEbt&)H2B?x^;^|;!?`xf1mub3h-)j0(%q}LY42zmkZGqk6W0>YoqT>y|HZ_W6V zmGRa-q2jq%d@&G0loxUR4*_X_lgxSl47SR`avO%gj8Lte&VfiE>Atrx{Y0{9t45|e zkHenGo(!ta4}yHPywiKSdLlkC8RN#0DjuoCQR%ME{Gy_8fd;3*m(DpUkJlNzu6%x(f9s+cWG1?PwtZSas4Ek!SEWuWgU zL^9XbO$YCXOuP1N#6!;~_F#OSci1=~4MkMN^1Y{DRWK@9ivSj2%~1kaUvAt=tu)*) z$Xou)f%~AGLpc_O$jJ{V0iig5zh!me2|REnQ)p&t-4GxG^Odfeb}+8|!7Krs&v0#l zMh#LW^kTJ*>t>xTwH0)rx=9ZGF<=uWclx?mtw*wdgiXwC`N2Zt-@ zOmI2xI%N5Cd%rdSCEy@YWyvVH&{Q&4V1k#F)N*a!?}$52(KTrP(A?$P z2f)`O0a&75hKCete%-FTkZy?ps7!)SDk&K2D{#BF|0e)j?w;dv# z*dqc08xtfor1*X4iIg;Pr5d+6Bnzws1+_R=-^QX)U7lftD4bo-Fp0N$tm*-mc+#ZL z07dj%g`@t;C$v3QY9@tr;f`e3cg`meen`znQtCn4z1P29o|h<;H`&Sr@FFpF4xI z1T@ct(ZB^0dm)1h*RgTG&)zi6h8%Yng#C;mb-DR9Zaq1;Y<~XOVhm)v4CcaWgH7%< zVpBFZ0vNd7uT0|G6rm!mddSbUW*$N;{afyyMwH>QT+uyML9!5#&MySARc5n+SGRLW za6^2nVF3lZRUFfe%EG#BSr5#MDl-Hr5afL^z;)D0sS_70!wpYu+)gxo!1`GxZZlDF~s=b6<@Oc_%1LDOi9|%?xmJ1OL1QUYT<54jK-p zQKdJjbqcZ?J*un5*lc>O$#M3lVRxX?I(0?~&hSvYCc9}-oLyBLNNtd)B8f)2*Qeq8 zd6M8o(I>t}yCBCBSn{DVKS`dq4FVJTT*L`oW;NnP>RWKi6c|EJkzyRmKEH%?;Zjc? zxuczxdNm}G(=|7+UYLfh$gdnQ)9oBX33w<~ ziPNP&U6G@C6+D(MuWwXLaGqi8Oak$NMiOKS0p-^)ODS|@S5(||anSTFsmn;;fQ#hd z)QHAgB^KKoa$*TaJ#=R;(b6S5()IA@Eg`6))f__8fP-?L!h~&CFL_nx*OG;2_qYvNcp92bXR(5V7>Hv>mOC)we)!V;z#Vx>A3FPpbr@Gx#7F z6a(A6bO@d84pZbe)Ksj1ZNls6+Q|ot5>u)+`YC|p-LD8GU#(p_^JT7r`-{5(frYUu z5|JHwEL{}|hAgC}a>+cw-bEMgBa5ZM&NDG%5$0`F$otM;4MjvfbdZpaPF(b=-4}kA zx)&D(AVG|kuc-J&Q2(5Vk*a17UsQ8SxCBU++SytxrLb;UP6EqH8JDv97Dd3GfyMC91vfGskoqxF`zKmMp zx<`|W(VGrH4|>W~KBhS9_lx6UTDw)m{;KDD(sFihSaJ5KB6R+em!IZ%;1Ez)Ow*R^ zwtwpeuo+wfmCwa)V9Sjvo@oe8nBnz`V~&WL{WT==SXa)P7ok#UvwfPZe_9jG$0+*z z3!gO9=38^N^#fNxFm@TXB}*Dlmr8(^@A{I)MwA;aUjrKmAF+` zqbHH?f;-t1P($uGtAg!9IquHBC8pz*>#I1FnA=(fQJ+A@ov>I7*Cp5ff}#xU-j0BP zU{&7}K3R6O_p}6C#y#w9A?-@71)9zUU*~+To zL>H1`Lq#~z$qsrmj#G_{Ej4?UuLjQ4JC2@aEVJeQ{Sh_CfuaR zF1j+R+*H^X#wV^Nfgb5%y|7P|Mo@(U+9MOG$Sbir2jZO6&@y6W*fM$-ve-+hNm0^= zg3imS3$N!Q0ElYl}=W%}Hem{00Y*5(zGj*!- z!5X3K!29ZLm&~7X&~eYw>qU0?BY>`nShsfgRU2eAkbLaUOi;v`s@_fGs9&x+nFYIY zb^j(!SP-oMeK6Wo*w9Mk0`xHR>Y>h*aQkx!Gv|mNiB_T$Fh4g~SWDW&#ISIt zZu-4bpF*d-^+;`wVP*s$-b;=sRfd?3sFdx~TsbSP$Mnzx z;NqQT&ldzS1~U5@WOz%r@k(YFwN2>v68I&~+o(dKX2J*X`FG>$=kOu}r|ZDgEo~kG%L6GkwPz>EpADFx6HVwSTRG*Ul7Y|Dn``M(^2~$8}%&4xmO0qN_N4 z#P_ubWM!xHu4>^6Qj*D+P?RNld5tBA8~O+UL2A=a#9_3su+%D_=H-hWSFX={v%f98 zS#gseCePm6eFTqGDl~LmD}h?h9Zuc!a|$eIh*YYmG*%}oul6B3j=QOsTvM6z>(tHb ztVV?sozB@nxG05`<5luitTzj~DH~EP@F&23@v8rZx7i@3#~dQY)7{7KLGD%ske{EP zcV)zGVd+J`e1|q&Ftyc1)UAPBfy@Ob!3>q2PL~0L7#G6xmnsf78E`}}?19Ag-mo$~Krm^VhShqksYrv{_Ds0-B#UO_&K6?3`?)G9GjuU$5^xjO%g54bP z6zSKk+tY)_eCOAgp&vqAynW+S^~U^$JI7rtFkx{Z^1dXvO5-sCJuL|2%Jbko&<&hc zh3@swH;pubAvtR-*Ot>D9Wlb?(9t9z|R*zqz!^%iD`?b&L z%Bd=DP_ypLp~^I1Oq0t^OhLt-p{z7Sz+@%;sorHx$pR-qN(&J&rW4cU-VBl|cX#L7}svwu79Q3v3nI|7{OKk@ARtEG1EIf&vha zNu#+)-=%GxtoB3cgO>+g3x820JH-)po~e8%BJLby*ykessy&{aL)9^rAQHU5(*alr zF?>%e%j`1bYkxG%qY2_Qz43ReG_<1%I|8BVKI9oq7%(5>n?FWqKhDNOiMEu!q@E6k zTl+b=9l<7cjAm;~K^Dr!+GrBXRBN|65x&FS$VP(qMo~54?-0LV#{mW9tJ0+&>Vc@Q zkxfo#Mr@$)>Ou!giaS`?@DwXk$LhlYdv~l1=2o-}1PZA%u?R51(K6EG?R8wsXjhvd z5^P#;!2>Vib^aB%F|-tGj}e#dfZX8ZXOXKWzGtX;Q#J@vg+~4|IOjvpDk43YDlvt* zc}br+Xi79l*YS|buCUw_wUmP4hewO^@M@3{_8Ve{Sns~>B$RjI69!tXk|K{>L)08&dHjEZY zjqxxIfl8Jm6AZo(!V8k=QrHn{V$5S@+P`wz zsI(rn)88R$LR3{}jAjtHfts6-f(SM@D-uRAVk`BOI6ypxZP`;fp`)VjQBIm+J=Uvz zx)}Pm+9T4>yeyik;|PY5AGLdu3?Z*#-clpTGd=UdXYTKo?`EQi^G5 z0Dx{4Psl@}04x`#1jcReGu7#PF9YhMi~UJSj~E|R z6;jsQ>=)0CpCsMr!wVV+SXfPmQN8Y(kZY!>d$e3Z$+RvrQ+CrxIQ#Oh)rXyvSyy)@ zWqO8h>8uA=-ZJxfrWM+yq$~2H-)#TDJeD+Nck(FJTCMR3!nV#2Pek@?tknt&G3z{j zrfv?4Li{q7Uoe~NsSp5JIfqZbW*Yh}dvj*~nRv=?ZkKv+Ad#tDFn#(-=BnBZ%K=`9 zU15?p#5Zs*e*mo-J9bd_Mbuum4!~XOW>;lJp zpXU_!<=QyM7%ujOS^tvWSXh*%2hKTlo|`{nWBa4?xM;^K*pJxv=fo6*;9N9jTsqao zB8d={zDb=<-RdFyZta`xMmw4qu+LA<6$}o}LrX4CYIvZ;GPqU#WRsw`24e=NAqEYa;_N>7y{hnoEbScXGM=GxXRFo#2L zqW!M;Yt$$fT4jeR;^YGM$n=^LKGNOVEkU3KD)y?p$l%yV4joG|3VCB$aJt1c58(LB zd}PRGPIvmMQo!**Cc!-3@VU+2*WW5QprevW_Rk31tqEHRVod)vMAcPmOW5jSzvj~Q zHv{3(30XwGUm8RRrM-nK-2}#SAYOE1kk8#40;$vShQ+yl^NoU8tJ!{Wdq7s_YBR<5 zEpA}8_wI{R@t6PcTKlMdq#3=YOUGBJs@QXH#@a7(1e0jH*fo1_hOL<$0}_3|ue}h+ zCcJ(N+g2d)4t?%?{~)}ctdHa=f*;1v%4CwZub&>@FHY{P%b#4FE@SSypr7gYhh|ax zKZFvL4`7ObUagL9)|nn)4MDavssS)V$PA;no4 zb3twCnDq_1`F&5lJX_8o!dtc@`z0&Fe(PnEF2M9-DY6F6b_W=E zTWg>gd`K@xejLup{VEkW_g@cf=5ckRPU*~8gSD)%!F z#!jAx0!RH682n3)h|!JGL6_H%=B)042Kbl6=0FHW zZ*>AQCTDq2To*qqJv9M0otfZ#_{qX`Tz_VBOon?N*N*@QLfx-_yHhqric~#;P+zmpf*s9Ew<7~t%+j3=q6-992tlb|T|>8$UHxDs>IhGf z6pM|Jl7(rzduRTyB&pn45TdqN2w*PkP> zV+cNY{TPEIOc`t#r4p*w3qFQh z=)rUQ@uqiBWU#cGn-dKT7Od^B zY^rcYRvfGO?tK%txSGK0SODMI>x@`8dC-R1V`I_&`m){-2{n@!`tsv$UIUs+9?JYH z0;Qp2-g9}|L}*zNs&zz6n_4jdZ-96h%RB@3rRq>zk;}IKT_Ocip$m1>z~Px$X994#H+Bpnz`~3 z$X(7uF7>R`H1rqIMkx1k;4-rXIjgSU(aM-O4(7GeJTy4v4bQ{(IaGEZ#X>RVvW8Pu z1z;Lgm%--9;C);vc`H%C-HuNF2!s1Mew>L^Ln*KjnA8^4<_&ua z*;HpYA58b8cXXvXOjcWj{^SpQ`tSH%wu9(+-^C(=)o{qF@8TkcD>ygFM zB0#LTu6)HG1Knh}Q+T91?BBFnYGrWe6DIoK6$J)Zm6}W(%>;h;J*ln?p`Myr*;u3B zmNVH|o?x4^ZiO-o#V3UMd&u?fqW#L~JsvQw0s+`}Y|4u4rss`sCNpL_5?rEjrj{CS zpKow9VV1+`*%(jgK`5k@-c?n=_?GL9P@*r~ukf608B3{zmcDQx)Fog0ZUc4+8*Zs%3 z8!?N$7`A+SA}r4<|3-3T6K>eFLdf`W^30yb;+zIL#MBlnVUOOBt%uF2Jo}-VFZZob z4H77$HNerm#VQkU0@gYtl`GRB;thR$BIrv6_)y1)lWu0ECg@E#cLr-+2eN+Yt$0jW zbzgMY)SGC|;W_?;)7Igw>1aGcbQF{U8|?0#0?kX}O07o>rB^ZfZ&fa)~ny zxci{M+cFh&7<^cM-opv(YfgO~rmotFP(yygJ@UZAsW`oeTeMHm^fjyc<|4eTS?Fz) zCy={RiTo}#M2hr2R>GNL+faNSv<7GRE*mvxcJL9sO|#0h{wE^qwAd=7nq2;m9Qntv z`uhe@^amX>A}dvc9_^Yoy{~`A&8sM!X+lUY3l~8^n8D5Si=5~jaP8!{g8lf{@Phq^ z+vR~cvtn(2yJksulBgMldO_99b0ci35v9db_qQ&ws-@G*5$o+1(wH4pK;dAm7HQJx-*+-enD3lT&A<8(pRXVNRVwDHXJVFqo{=)w$ZruJ zzqqfIVg(>BXHmQvq_pY95cKRrX?D>*G(XI)VR%OEJ)dM6KFMK6OAv8M0(zAp{c{(R z9mMC^8phOE&*sW)tP# z2=24vFD|viZIK7>0{yPjv+CjaDHM^2ct#o!ZeWpG)3iBt^7TUfXu1dx*8tUY1|hS| zBab@k^-cRRUzv8oegyR8epZ`|2rRX^dQaW)km&H3357Xaf!##a?|Pie+yg45BxwgY zNt`f_RY~oZ@LC*-Y6Pg#EuB4 zG9%=(m5KhlwP*#iw#ac&^-WWss|1Po9msbyznXs696Uw?p#xwE;dbY^EtalT?!3H> z$fu*G;R345S2f|!sHgN@?f^mD!k4@_*3T*$e1^ALiJ8*rz#v>Jg)pEX{;*wJxwpuj zK#mk}D}6zxF3lsA_RV1UFC3y1s3d#}rj`zfN1-&(t1)^_lt=(RVuGy*Qv3O8DNKVf zl8(?lS#zu1%pJ??2fvfxoHC^k(LA>xLH3L0Ce2j-T zEhnUgW-T=Hx>0L~rPCibmZpH>VdEfD4~hI!Xpj`C$^;;AZWUN;{k*$go$ z#Jfuv$VJ51t>x9!Hw`RSLkvs8y(lXxG)I0ffAR>M_#o7DKzf1jZLW^k0J=MBDUp;J zg^b~U*050u5v6|MFYF1E*K@jiJo}FUzm656=H$*^8;scqMyQ?k01Ok6l+Pe5DTB%S zVIx+giXV1{Pa*+0Hy3dBL8Sr!tpPY%wtGr{wnhsW)4U}Zy&PKbrv{|+cq6ZpT0UZ_ zdSC97oK-&$X5v5rXv=jqZ1|G42l-^J*@ZdfB2MXTIlduB*v_~D2Hx^3`%ALUWef^1 zIPjA|5xBoxKMt`pPIeQqa{?MHxx34}2z*VSx-bFW*$eNK*L6l`G#t6?IeZlc;A<^; zjqy2yLW$aS2VGU(-nBW8!mhXgURGvNmmhmlt=vYodE9^)IovOLHonwt6SK;1Qr zfDDwZZ&WUJ<76@cE>@Vs?(!NHT<%oCW3f;HJG6z=!aD=*-GAMT0}$eK-}vV)*OZc1 zPtI!=2mY(Lz6-)SXqm_1)|QGR5gy}N0d7B!13Hhlv`KXqLLK} zuVGW!x?>mDRmx?chdi(Y|0w%$K+>9^%!*`c-|mst_|L{*+_GSMeQI=J5*x1XceDIi zyz-`6C7c4j!{(ta(r2Fg;(Nbw`-8m2>g4#!qe8Cn+Bmd*qRid;r(A)vm$8BtlYH)9 z8eq{3{+>YOccf!;2fde>t*DW!IZQnSg4vlvlSpmmXz$nKevF?=qTAX6hI83JEpX^C zma}>S2f|^}&D0FUe@-?a$#YT-5kt3EZF0zvZd^HI*aebn1?o8Wa)Ti=XZ*pS~A9s3OgyAr| zjRW$HXS6>b)GI)JJOUH9+PnSQ5K;z z_%OmBcn4bL8goCvLT|6rdU0})g!PRpPu?*pPnrE$b(zy$RH@N54L;Xp7Ifg^&>q)U z>3IW96QLppOyFY*Mi1G9Fpg06@6d5iLSvP|0uNH;D<7C}Vg~KDJ|zTn=k~IPfXVc? z>m#-1Y(K#DVc^}fDvDZ88Dz91j729+rsp55HQsA#P8x5s#f)IA6wc&+YKR(D$AM#4 z*H7-Wh?Z@)FVXBu#mT@6ykBRa6V-U#vc9g~YD?C7<=4CR5oWS{1jH0sX;dwZBy!-L zmF`pLfF$@--jhZ4$J(HltnY17h=!S=P(7$)?*2pM>xKlES7GINgN9F3S&Ru%RPCUJ zPw_@cY^FAy8qNSudDZpdSoYr{$Mc>_&XGoMZ=Zt^@ou9?qP0tU`QUU3AY=}37f|mW z8>CkQGa*$CB1Ik`P`!t~u83&_Y_FuctfXTqXC?@2-&`^qo7d0(Dz5oxqI{0AS90S< z^6B+OS4aVVx8gEOa$MleE z#AjEL5ZJ;a4*U@t?^tbmn^31VP7mDfw6#`;11E{xWO z-{&ul!Jdem{1T1hzT)v>uR!Kfb)F2YJ@zoyr>1^`LFgKkNlOC~R+ePTMJ?4(^N z^s4#%Un`LQ6E)2Q`xy}J@^K_E7i37C5r2DsQ@!WG-?u0V5P1{>p+J!h8eM@u{_muz z47RonY?} zmmsU8C2m^WP+#p@l`kXY#!As;b;3TDr$9p&be1%sz!SR8M<*6J;pXc?*!P&zTx3rc zf1DY8+_sT)7z^kGB?ep~N06KPgVcvFcw%pV8^Zzjw}cxb9t752LAQDgpI45iP`b*u za*#7r0G$Bs{=?a)**I0DM?lo)2#N=~-Y+0lW`yA8t{0?bR2K6labl@VpHW=w`hx1f zmQBB`hkiKme8a!)18G?Jfz*7I5o5RC4>2_a_EQ{nFfAntOkhe|Hpw;hjY-gk8Mx{y z@Xgy>szn9j>){X^sq7W_ooGCud7&vgb5sSmLL2c@GYF_tX6q#`GB)@g#@Q);lYqIxz?h*ypoeICH$ zq?=F<3{{m-F+r_x;xeP&){a`Tx4n{-#=f-7FQDcLXjz>P> z|8foKfGziANda_8H_pTaTPfWhu2wTf!`lREP8*cz?jL;jV4fn+(pt|R@}0t!)>Ut6 zD2s}6EQ83k=>6;-a44ugwdWJ2mI%~h!&iQfG8bE(I=ex~*G!^?hZX!)QxSpJ^`@*M z9hQcsGg4T9NM5j$#J9CEL;x1Rr`x;a6N(RPRTq!3Xu-CjN#mc#ajh=P+I9Zxdp#PV z42_wTk&+Nw(wen+K*rKlZ_a33&1jn{1?NjE>~*PFlZGlt$PwNicer)o5(%Ce+v@MM zzpHxJ3fwgm8dkKue&y3vo}Br_O0?LgchqB|3@LI$Ey@RbntROpX;C?5Fl?gO<|d|2VhZiq{qx{b`0c$?!S7xw9Fo;N+k zIu5A_RmqbpPmMHsV9(6&7SJ1NpO77(~1lCa+`;aUbg=7B0WIuURO~4 zy(EuRUHQ?oM;_K6>Y-?6oY>3+wJD(q5gUbZ6H;?-lt_-YAXWuID{(F-CH@$~YlJ^& z5CBYRLAZ%|UkiK&hfmcri0D0X<~CIBNRs*sO?3*~!pX6Vb6-$zL;eB!r7_-*3|~&V zf6tb>ptt8A-Y?I7dSbyz&Gg)VbTNvS!IjLiF^R=e*hsMHIfIabyL!SUZ*IUeK9R2I zQ_9my#(yLHre*-FrVl6SgpFE~D149Hp&~JD2UZ0J0^w|#2LM{k<(dE=))mgd=(Jkc ztNQ8b*6`nnv(a5G!bWS27V4jCbD+(Mb)GIYzHOHk%ypjbSEMWV+Y1;Z(6qnls&zNA zI;&t6+{po+>QhE!vViwPRclELn01l7=X)F(8Tueu84F;y<$h@EuU)~fFZiN%U8pun zkYo0>S>eYX#$m0Tv#LC9?mJ=0U=AIckkL1)g<}mwR!mNqAzVG@+8A&S29M3+giEeI z^(6X@2+ARlr<#d$>@G$DyaQB#F@mGG$-g@zn3MB}SA5gc;@F$DQ!vq7TA@QpZgJ_HS7RN^EE`Ocy6b*KJ2-~NlR#P zRSzE3C;Fdn`tRHC)owOojFFs6z94mF@cbk%<}Nrs87};VhzA@Gno5GEG;d@kIGIZ+ z-e{5YUa<9UJ99nFDgnHIDxKK?HTwr&|C&$Hc9~$z%AeKG2GNy zi~3p(Q@p|Qec1=+#8q5F(0;kOhsTriHbp*T18P#*PUOhHb!D(_yv6djOHCBOJPojr zfBn0T8BwXn(%op{|5%_lI03#MYI?65wpZ2LzOItx4;B$+WilY_%SB_^V@{6pupP_4 zIpW>5B+4s{&J&w7BxQj{&p*W#PvsTnhTCsaoPfB@NU@ZW?fQL{3EyebR=rUth|jo9{@R3iF_t9Bk;k>XKLttip~8IDZh7qRhE@eu* zge1s7oyR6&nLTW3&o%+|e+d6e$c!E|Up_FDuFeL=gp#s{nHVIa<^Wu9<^^ena=N2? z`=%8Nqz(xX|L(?0&9f!i&bZh6+R#`w~ws7x`2?6A)EjH6T+NXwb*i(;&|GFAj4 zcdVoe>Y5^V6(aoG=;NY2$Lo^(zm|wU80j zG=$=f&~b#>H{RGhCq)s7FoZG2tH$sCm(UZd&BFkVd1ay;_XopA`nZHRm#(r)&UULSd|ZT&2z2yd>Uj-9J#&9b9C|~+wtaBdP9S= zIivv*6R*1cY>Sl zLVQ93Ri=@c7VGwc7VMy2$qfF|x7(6;?->|Sr1EYMUy)1_k;OeWh!Wz+uzYg_0x16% zn!mw6R!pv(ICP%wckijK{_Qf15$F_a6qBr?LTWDIsg*I;7O7fx$Z4sWx#Kz!K^tZ} zgL6M6U5{q%iyhaPKa&~BeA6ZDpPX~5wzASZV1SuVX zu$Bk%gk(7*}knil7j+4z^B0Z^*I$tB_w4*%Xrw7dG;bT3$8d;=ZNGz4x-z0w^Q9~ zxWIQidqV*1g)UdR*R{$3^EpyU2?j@3NgA)QSXXrkL65uEWK}aNWz!FX1Jn5EF{1Qq z1{%VqdUMDgdo&4pc*Eub8q0>D#9lcf^;M2$>G8x&szRL=0>SdAC7j*r(inng_3m>r z54TnnCA7WMmQIHNS}wNZJ9H}0f_GvX7y%0)OSRgu2@Wk}cr4>D&%K5;zZ`SWI}j)o zF)VzScMqO1(1Z6@ff}ZVdMjOJ^{71Cr9y9}&%zC`Ugn$9_@(#ziX87y4r!T2Z7M~} z$8qXd?q7(8UK3cCGX>^%7ifT8)f1ODrM(T&ZkIVqcy?Lqb z%mB+bqkkB-{^^yo;?*1`GBGBLBOC4M_~d+IIPUyUHLjmOoL93trppWBm?JJ;MQn`%>wCpD&nu^XbOS< znsp%&`pSMmr@VT++^sS5&$_c77QmlTWmSDl3TJ`KHWgO$1-*AcK86jUK-7ScU0?%h z#G0I{#>d-WMdS6<@j6<0(@z6y2O7XT=VG0~-`;t8T4mscsJ81tUnvp!$el$2c!;xb z4Q7n@(W{2k?8{!Y8^a-N>Kp;r=ywp)crC874>!@{H*$fJ(^!_3RZ2BJbS-(%xs@As zW2~ogwSy!*xA+^PjC8re@g2m`rZ=YoEQ(ph!20dk(6Lc zWmxbu1TJl_yZmM%oq_X(LHK`AYGn4Zxpc+2JzEAj&XX&Yi?& zb~F@a-9@!O=T_}?p@8PE#(j`}Z$bw-XT#mjFgE(|itsz7CfFx`@G`WL;t%f;rU5rV zz0ddo@fshUij%L42Jd`}Gg1z-h9(SyQq8EE!}MORwe&Z~>7wIGb0klw6`BEmbOeqdKzEUxCO7~5_3)a;mFkp|xwZ>s^Y?17K@ypSYLphlY^15}<~YJ? z++YtiC<6Oj`iBZpAnYx}nIJ%$P9RT|H}Tb3Wb%tc22&660Tz{>{H`Av!{iPG2?ONu z^y>d=ho}5oZF`!i`9PlcF|t?OMDIuifpf6mS4bQkR1A$9y@A+XTXkyE4P=CQl3?f- zSRLiRn1DY-G&iybtd~SsUr{u801h#Bw9i_T&*b>{H#fn6?cY^^3NpLeaQKT0z2j?a zt+MKw)Qm59M_JkjY$-uX+h|-U6)ROvs$M%#)Wm(Kksuy85K&!x^dx&vm+J)BF# zEbBEs2&N&r^$(F5o0^YTW%gwkK)wXZJ_9hxPmahydxdxq8^6MzX2y_Jd8-n-*O#KTI0=i_qf9qz&$cYSC3JnANS*&0JvB8o z6&LF~fq%ZMd$&pY%9vuy-)cPXFp;u#EHlk-D*TrZxCcU=Cxy*$8K*xGn9bjZhMSXK z@SdGn_{&rPgz8jDBcoQokVXiK#m1%gyFgUui3;M~n?TztBa6ra3D2815O!qpYDHdh z@PT;M^#7-QPfGgwi~?VYR*6^ji2)96B4#NTf(f|M?*<+^OCQAwU&baeNKZLKPZ3br zCwr{;M!_ zs(&*q`{`Yty-H_=((K(P(XhJ)F2sq>Qh7i-g?z6-Ma*CA9HBr@oy$2PY^=jl^EB30 zF)?~(q9TX#FeJxO9h8KSWR{VVYCRhk^iyQzD8J%i^vJD%o`ulHFC) zCYA`{C)-TmD)X+Si>;i3mK!X+BRi{*1T&2Y0&fWb0m>dqsIi+BL<6wWorajZ$I@wx z+U|QTd;b^pEOr101iBA;0>y-}J}n{7$?}K(e`iv7OxP0vFet+U^-b_h@rjr!{9z0s z$KJ~*(cSm-0X{x!c6wXYB?JN+AKs#Pc#9>a52#vJ8Y3tIwV^t_qj5_+R()^W-ifY@uUe&Fga1qvnm`oIgn$QXRx&J8SO#0OG=bFK1ytY8`K{=^eIr^#^p zOcJN5mpQ6mAk7sUdfTx4+xA+A1WU*Y{kd+LzFjSxM%I8R`W(gh(bESdGSyUDmu~TzyJbrRDovki31#g-58`PKT`U>U;?+2&cy0! zipyj{8vp+iwg3JAJzkNOO(Gb!gJ&B1Fbw?kW}T#I9RpuVlR~vp1wxe=n7dP(c7A?D z)e>VVLEK-!)d}^s;;Y3Aq)+P(-x$g}y3aC~)+-Kht>7_v}HcM238;o|);IJ9Y_oOg|YH8s~ zh7B-Z{A#kCjs)L83!%!^Z2~~TxM>_>q;;LpdUnusRVh(&mDJp$bT32l&?fxzQ8N7$e>Q z1EC*7+U-M1Qlo0MlmQL|=P~=Ty?Gs{-gPJhKPFyUIipUuD6Es3dvYFjGVKOBEkdBxj~-rD|C@eUwi4g+osS5WPYj@F$;05i_k~{;3CdWm=KL(jE23elGjY4p;ADSMVw*2o zNERSbA6o&J2(vvel`M$P-$fagTJ4VYyRCC^Ylnlwx8h~ix-=d89Xu|2q++CviU$1# zHT+}W3jLDSAZO8BqlUW5hS;1fN6D8(8E;QtChu;EZLa>_fXl}woOgE%MYZ7Pm+JqP zh4Mbs@e~^MaeHbM+cIDJRCyQS&vH8-X!Ij1g2x4iBQpyqME$~GqeDOGD^1tHe`=)N z)EfQdc?lQr@X%64Z_q$=isuD}f(d-bTj-bUzNz<8NT;gD*bl!=q)uvydjG_uY^|`k zfB`XYg4p?~JqEZ7dkRm5B*1H={*2YAXCZ_~|A@l+_$J%6d9K8mJZO&wydAsk~w0JNAf7NHuDikw$D`7+)l z^$V9DKShx?g8lm%2vbF9#t6cH--}R^T25c0-UrlCJ3tqk@~NyuSZ+6N6{ZO({7G0Y zbYipqqMB2nY;7`)a+g0lnaf(jz`R`pVhaL>@h|`d5LMZc#ihrUqxp6z61{jXK}LX` z2PXWw(QR?8rP0pR%AzGE!shPNllOxImM1Vi;%^?1q1L8Krz5;?rWcivjEsS3s~LvX z*5P-Q^d;&*oGAxLtEY{`I*ktqbn(GtFo~`KFODyLxHWKni-!EdB|dVCgun)8FME3X zxY?|%`e#N+#!yAFF?q8$C=V3LsaMnw)WAFU*T^Z~U3%2khd%W8kcc7)BXJfbgI&z}e!IN5pQxG}GMdu! zpFc;DJkO{6$6O!^DL*=p$V~IgdNVlfvp$QM8 ztSa59My7%ZJN@zw-`mQ2wug#j@>wGb>r_z8^@nw1kK{^XzLU^JXsQpQ=STnXBhK)Z zHGU0##^|2GZ^gkSS8^KM_FQR@=>kb*>V&%Kxc!eH?$TH^vmE{WS;AP4uIjb`MG&u( z4?Urtu66w$H;&RAA7IE!ZgdoIG#qFO(OMu;S5diCV3EMRl^y@W4!Gb#rDG(sGbY>} z6!qvT(XRL6hAS}q9R27jT7<-;_GY~Pl@lm19hj3G@wq6;i?wB7bP1iQchYB3BT}5c znIjj}DvGW$5YZSO>50s=E11^E<2z9TMcBKkMSvue{Ca7jeyG+LGXQv4BMNumvYMma zB2^|2oJ++Q3q==Bvt>Jzx#v0++EP z^w=PSv7Jm=Wv_)sY4GB}lgvKm{T%cEf&N^C*MXY`Fo>VTbl^9_;tezqdu;l7Gu<_P z<$#|jlAKThr`k=Vnw8~W2MmNixWZ`fkz2$j0COy;wjnSNHp8LnS;O{#&yBkGPcaK~ z3T%aLm7KTQilE8gEYpp`7fy}aLz$-j^!ftzHRB9fRugQYXs_Kok7=FY21vq^g8NJQp}PNPRw18-p|VFl!F!Fk5*y@I{QMI7 zgeg~F&g{YCxKrgA_i=!~gL%2Xx|+qMLftUg7IWR|NO@uzDY*bm`c}+P&p*)A3+AF@ z@-;H})xu8xf`aa0Df=$+fOZmu=YKdTXL|VO zKrJ9@lSXQC58&K5;4~};*OYqOu>41KU=HtHT2DOx<`M@K%*>;`S5`W%wDWLX%BeXQ6?ZEdpXq;x3FrueTO<+*nku?L1}r3xYiAKq0_gNC?tDMDV)WB zqih*6ak3re>1clDW4`3ECG5j<(>S)VD@+W_i{L1fxw0qb7@K6=g&r^^mi&6r@h5wh zY*-NsJjjV4_h)GU0U!c&rp6|q7j~=i!9<1wF#T%GoAQub@z`@8H>eWMxtYQJMwy{K z*7)qFkfdP_+v0mvwFD8>hj9e630$b2Hwo^Q%@W|C0}&=GCX6x5UMO)K_&DHN7*A3; zq;U+5Q!}4xa(k;WL+qz4@R2GUh$vtxJzP^w$hkH_8g*U%cu@QZ*o0}_ zHBke{#JstJsSJ%+FY&KqDTwYHG*2_pQa%^Ks4yM+__|reBQ)0bBXvZPD;z zoJ2+mG1J+Y3{;`4W8U|d*l%*Gf9+XH5wtEKCls7L~g)~&v%caoITrY8<4WzGAv^MRd%zYY9?C^DAmtHwI z!}9(tS!_`PxQ=2(1g-8B?|PzbONZt!P)l#CsD0BL(I|tpZ*`iJyG(y27ez<_;Zup= zTpPbB2M%WE!kA)6Y}Gs?m6_MO{bjLCT9j?KeqqxpMkc`u<6J^;M@+opb5@djK^rN) z67A@du6JKoJE^9Nrk{m*${eMBB&M16@XPBo#4k( zg>mc1b>IS+>-%v(l-1ygws%9<1$dgfE%3&4qf5A%Qx?e}AT)qd6TK`31yr`EthPfR zR90Id&v!ERP0*tClM?j$WhpxCV>kL$ z5aWG8W7`{H*o;u<5~)BGv-ki5%R6c1aX)49olh(Mu)^>f#h2sU>Zz zRF5OfOl&K`2doq*WVMKmHSM3YdUf(s@VWgeRft>hze+gZ3}@PnejxH>aiR3zW!Ixk z1AG=2t*6<@88MW&(L>bZ<(@vA%TKT4_z`r3#eQ z4FpkJ1r@MT*V9@AeKX1!8Ge)feq2^MxxF(DZ^*AJh=WKlbwOK?CDWm|TeY4F^hzyl zO`xds6&)B96J<8`hLvMu)>c3O0000000AXCzDkY9@&{l5MqzvPvX(yhsPD7)yaOR2 zJtSTNHdBp$yGek=M!2ijtvrfNQRp)8^>nQS>Kp=Vaf7cn9PKK)?g{m1&rnzzF#mVS z*!Yo~f@x*;>K-?OQ1zkZu$2FkxQ`QcK&M4;PTdr-qGD-<^)e~o<~H>idP3;7HW_r1 z59XNjs^A_jd~WdfApdG&E@R;1KGBZZH-N`d?ap*J)-$V!KJ{nMi~LLhhmCD3;=GRQp;g(cwrt&z zu5;|t_~%z|P6;~eJvF`Idzei}hH3O`T0GCoLsTj#;#Hy?Xm`&N>B|j|h zi6wvy;SSl2gHIO}qn?H@B9c~*b^tz@I5lj07I&|^b$V~wqEotDG$a^5=!$AC!hB2{ zX+yP)tMpMa9G`1MYEFo)q>Si6i7EZlW8OM`d@86bM6ZD*VkOVj0VWCUG-~h`vxaUawj|jsuL4J;L=UCKb8?OshC2o{Dmy3M1`h^t%uMD!Hx^mUs4A}T^j0Pm`?sDIA5UX~LngTXmju@cGh36sbqqpbrm?d)sH%L17c{o=Ga4F+S z8;bc1bx6A-Pr+W6Icf!$e4e$vzN2Dv5M5#VP~-U489@vvT#BOkT3TA^Q0j{H7oCjRWn4u>tfgPz^OldytMI4 zo!CPJi>n-DRWW2UUr5H_-A4BPpfh@QsX~;CU-@0=;(%a7uw~PuJsh7#A0`Aj zHz(i2kQQ2ZQ(!^OW+c5z9mfyGPWE(pA^z265!yPr<~1`5@^^I((bA8nKInTE?HzzR zvG=G}Gx$G690IbyhTPx>kHxe;?LR^FT3NGS+RPW~aGmyO4Q7%x+h#lsGYG$6ZzQ-w z36>Vd@X*djuJ(bUJpwJO!~g8RWePgcJ@G#89w4jiPUnru6H4{aDWWCL{uS{yXBJf^ z{$g>MZw1l&kff<bsUjSgR-C=!) zeS-u6uRx_O9jNfM7<(R=p;L3t7iy8D|BAoMow_uxNJ@N5lx_62TS`dshhOwzvTYxN~r-)PgmY6tM`!Y}zXdpW=Hcg!gp zpdFfHe&o2QWt>RlwV)Sl-_mylmB>(=Oh5v`RVIE$gz1=p&uzP1Q>jn}hB1$0RRaJ3 z0015ms;(b)gFpZUg+HCW53Z`!AHN5zygekC!L%Zi3`E*ES`Z{LeVhc;<7#|~vg~t< ztG%L9&xgcGP2AR2E!7dAZJ?;w5?sauJgo#QFA@k!clF649LD#V?a__+QifRlie6WV z%Q>d+q&m^jMqtfNE8S@a{hSv1wi|@53-`y287V^0^%g!BN+HZUoS-&uJgtO=Og#n8 z5KAQeeOMf0Nk?XU*~yjPE9sdeLJgAJmK~^J@j7UIDe%WoNRKs`9ZfP@1UCW=;aP6= zo|Oc(tQ}+Jn(7jv`8_qOUAtze`8&VD%kEytUcUAcs!$!l6@*P9a8N zgl`$;*tVQW>4KPk$Ozr-yg5jQvyb6%H&UDYxt(=bamvZkU~hdEBpgZv<&pC>sRPQe zUzF;w9mSQGuq8Azy>WL#Vuj2akQtX%eqQD^tnzFpj~IJ4Id=Tq9m0z<%5M3kECr85 zC!B=(5mXMs@d|_N@wTAs4;}9Hu?5+Y_iATk9wx+o({D|cu>N>$QxTYDrF)mg&Rqee zOCovUdU7I~P9)k=u5%ZJ@^;6M>l)wlj?!3J39a zYz{RRCrI}8!>Wk;ek`%^dcc{948dVEBfpI4=Ww6V$7n+yJo~jxE29R$TU#veKwp2drrpzAH|j~()8D@qY) zQ`)U`gbWDt=wh^4oGf1mlcbV#f&t{(=yxS&`v+LXS%nr~ZlCh_hxcZQYWJ}`)o_J{ zgvjCWv0C9+{y6xE$2}Mo(tnTP)Y#jhNg(dtm^tlD4P|`OF zq)Zk`<$y;P3xA?4t+LohzT3vVK2c)EnfR;0 z(eqQYDdle(`hH|Ps3&Tc(x^%vHXi`QyYi5)+kdcVio06B3Ia|8&rK9Vjff&jmOP2o z;|*>RPTZJUwXD2s2Xk`Q;tNsu0EjQfA(@2j0Xfez(jS@J)2e3WK%jEKAP50Ue!|ur zGZ+$R854;mehT^SEEhiwDg8Eseo<+euqL=yv#s8pcIgSQB~8h9J*C(pUN+M78^*L+L|qDW$*_v`=t zl1)@?MxTanbf)nMN1=&-Z+vi{e@!r~Npad>?xzR${z%0EYTIysTjZ?)jU6&x@>oRC zAf-6hwx|eOvKj!i$cj6Y2yC(}g~*#A000vv*=KN9%lY|rruATM;lLU- zd=PW}Hc*DhM^bqAz&-qRrednF00000001i5Q~+dLB+rT5-I0NC31;Yz;QURbLWM*h z=M?V9Qw&n53bY|q3SjSftvL7gFv7vQ)hk-oC1B-s*FVpSM0YaYu9q)iu;~a%u4n)N z001mmpZ?g{tyZP;3%bAn002HP2(Qj#ai|qn zn8w(V_)h(3p*;9-1I}cO#HYl#$ze!XR=7GpzhqZ>*8QJX-_L3Fdea|@U`k<%^Ho{Q z)uw&5NJ`bvjPAs{aL}jF00000000000EGR!Y*HD~I#HCf)*GR`AWHWFN$NKmm=2rp zcM{jX;Y6>b#%Ig%Qx{7UK2$ponPUDzXy<~xDU?06P^Y$P4#UQCGMY$UFcO|}L|Hh9 zu2;1D{io;X-eSVL7=O!V?)Lzpm001W) z5K*0VL_Wyj0=aBfaO=rXwpHFZD#28H1p}O%T^tEhod-TetpSbO)3$uwv*!09;&39b zU_`RJ?+yR}01i0_3D|l;eK8^yPJ^7H;VZIj$v`fYx4JBjdT3=OD6G=k-*qm|J=bd` zze^6f+nm5)4Bf&qvcO>dT6C>2^O?1ihF;U85`d)hG1I^p(&#O%gl1#Hc1c_o5(w}B z002^?L3V#SZ&6BkZ_dK^2Injw5&d^K5m4|VfTTa9H~;_uFhCHC(X((Xn{$@o+cIo?eg0SPuC=Jh!6eYWf>e9u65C zOR{MlbvO}Mup(P27@b7AwGx=rO>$5G00MlQ{kR3x!O~-7@ZMhf1Cgan5KlCgm-_eL z!bQv=+#u(-6qxj)lx$~O6oQtke{QO7;q~822tf!YgGkzxxwavnt5^8vcLU{bKqx;2*?mLt$oRG|NM+O3$t?ka!dUSe=I>6M#TYV|Y zk)dt@a?R|0;*0+(LX{Z$Zd6nUsgv^tUE~s!E^w1w_!!pX34K z1RVR2m8ESB_HW_ir{ z)+r)zQ6bR3~LrQvHO&nCJVTRyX;QAQh&?`@YbZ9Zq~KnuZ{c#&(G? z$Lq+GWhR|P6qH$iR9>KY8Iu@t55q4Zr932Y&i%lTSUON?wy$W`MQZpGBmo+OY6VB= zxc+rZs?zp_kAhSj;1tI=k( z>Xrf(3mtlSbvbSF>-=+&pvmFXG>AnW>XP;`o&(5TvGVefu+&IWLoy|rKfFTs2$tcF zd?iEI*QjC_FKhVz>?K^A`(8(LGKA|7yOF2hdETf?pNwzHrcmO{h0wMk|&5b z*H}Ftxc`4L33uEUNZuUcdDY!4z%=Kxmi_%5bX@>0m2U*-s|4mlzy>taowl6qwCGm2 z*DgZ^*=FMJ=+H4}9*bU-`B%_j2!BP|{`46D)*o({uzZYSTC%2Wb2!bCB1e=2a@59t zG&Tg#8*d&J42BW$r*ObUFd)}v;4dFeCsUS*1kt>?P+MTD4lnGxV}Y1Kbf()IF1c9#QdbnpGCTkeq;&uUNYE%?zC1g$(U;De z(=}1O9A|8R<%DGP_(r~;l=NCtN2q`6Vq+*@1A2tl+47B~YPl>R$aJD=V;I;o4Sq$6 zlI5wAYb$e3L+C%nJf=VBP8s4?C@sBMwit$dl za?@CX&(lS|OK>*8LwIm{T_-6vZDD4Zow!7k;d~hOZ7=%f_m5BBh~j_dzJbjOCQg*DHX?ruyjg+Lh{6F{H<91qs z?6WTdb!YR>qKQtyUr{6FC&)aV3R$Sn>2Mo?kFQP4VjpbPM8Keye$Eb*x6~)`(L+eo zJMJ%e-0p~gbL5y;RSHupEHk#IDo<8l;lV9kAi%c9W#Wk9tv$b=O2eSBn`=8=5-j@K zDH2juKpB|B^IR$>9&)Xnuu&5!@11ANx}bgaktOGEbdt~=hS`?-zdDVq$j>AAA^Yn% zOvtB}-@=m`=17VFOOdzu*JdeB{@DTHv^bQFT4kXD%QmiksfLd~x4B{-3xYTos(^ai#M_*;DzzDzxtZ?Ru&$MCPVf9vUYNBClVO@ID=I(~=0W^ado z zVfOv~r5Az!+xPc3;FssO>+ANP2|j`^sn7M#@0aU)z54Dy&-n`QCHV6HDtUK(t@-Re z_%rqXKJoo}h5uyr?c0`fe*6tTeG3szS)}cpp@wU^IIPiNcnL;`a)?R}TzpZahxYqE zCBR`@S8!$CXTEZ+^_;Dmt1q8K18L5t)N@pZYQH3Nb@_%M$}|f)=1NoWem92FdKR?b z$6Hx!IU?~Sk%w8DlghpVjeRv}l4`$lt(w8y7{t~b1%C-AtJ!;txdjp}u!ZMt=mhPd z4M!JR!{+14n)en-N%GH1*kkUvNA0^#JavYo0N9bQZUVH6x7fG_J>!+?sp@O^?oZe< zW-Nz7Q#AP_SaSMjJ!( z!vzNzh7e;Ti`7|tNDjGx7}QR^g#LKKNpqDbE+yuUNq?Rky5*gRAa0?_ioqdyxr+_7 z#)6>e=G@r;S#seEkVIw_8g_^NlOGbm-;JCQLz75;GIs>0TR-BZX*;t6IVFIo(U_Mi znLTmT^v<0pTaG+&^x)rv7$%?U_CU&{F%zaV>0+h-8PuxNU`m1h>k>0FHW*9lBL1xp zXjWaFk|pxEpkj{14kl8F1{;Mto^l_;5GyYzVHbefz|m7kHvK3f4>bj8)PNeyWm6}q zLIjQKyUQ2O-j(RLS=<%*KyM#QxXCY*t0>kP8WBFolS}xHce&6M(nB)|HLK+}pJ|W7 zuS)M+LE4)G*jpE$cu?6k!fvwuXp)R-miq*SB{lg|POd5Jyed5cn*(`Wm#NaU$e~njGjlrX)+AzR$p>sC)TZ#@wWu3dlPJy zHJ|`v8|#SSnAq~xlPE=(2`9B{p|k7iIf84xnfJ+73fB5DN;&-eJtxGXgT98QN;;24 zCPCw*&0RVfGGMD(0!d4csw1#%WB97u&>VFm#EA)bGqGNe7U@q5AxS7XfTFe;OJ5|iMoq9i1kT0Q*ccE)`1-6Xe5U)CZ~Ys;!3-^RHnf=Dj5U-yLx|nbC-PPhZFShM6tQz5 zq1b5v70H0AzT640cm*X#3L5h5RXdH@71BoCvd7a-{na7d!Ade>QG?xmaBR|pvaOJP zbpTX=$EG}gvMxj4uR-W<5MN{Ua!*oQUSe=}%uG0xBIzsv4ith(+LKNF5gPA|!R9RK zxHQrb3?NCH>ka>_b+mSbnl)8HiEvfO-)^&fa0@r-qD&>-AtOBDu+CC8pY=hZ^I2Bs z-PmqR8&5i1^#(Df+Wob<(7l;A0;A0ux#uYO>X|6KiP2RA7%W-ZQ_vZDIG5SC zlSM&r4o_e!jn*s#sgu+c=`(m{eoGrER{-n*7g0&t)RU#jY|#JzH3Oz zvOLl88s3J85XN9Qay(_o5d20=JMZtF+FB6t2mx~{cU(kNG`X8)b$Z#;CFWep=yEm* zp*d~`$m)9_gnRQ8mqn^xc{@Ogm$}WUKbf!~>|%lGXa8=&UTR%v1teSRB|pkwAH>fI zj2T22efQXj1*%bUSeoa(S(I{}Qr}#iar|0t|4TSs$njoIH=(vW<-^%F_3ON5`IqVhTU>Et|H1V;tCW_P&9 zYj{JPqX_44WNP5He1j1qXur=K$F|{x2B^ddXlyI}21JjYHXkC~ILwF4sy1R8*JtcI zr;syD1;Am4`g-#i$iK2y6cw~_t4_+|8L^>zay4T796{|G z$+}QR{WWO+sN5`YJ4`sNAj!l?(>Q312lT79{67@*oMY~Nf^x{-@FRI7P5xC^NE6(U zxgM1-$*BA+#aRM=`65F;#vijT8_+)vk=az$nJ?GL7SdPHQ0@i+?b*$_5pAyf<9qgd3)x4lj>nw~|URo~Fs-!OmXY z>EkZ(UJrNMvtKy%6}XPUElWjAgXJF%Z$0NuUZU=IhO(n`k6ff^vIxA^=>=)V;ekPX zm1n%;J_?Q|M}0h1I*fh|d8djFYt7ll0pu7mM12btY7K&O9@)W{1>^#uJ5Ht7*vyJ+ z5maOr+VPvP1!FD1PWW2r9EK(qogp0A8koDm?9#=z)RIN&XZ#l<|4qm78X0%M$uHvc zpoYjK#O!AvY$!>zK1lM$O@4cR&0sBCwigECk%V;B(d*}l?zq3aGTq2`e+l3FA-pdv zfP@>anqVC4j(&_fgeUyT{dKsXsN(g$h5DBE*auPdoGUH!#Rgl^#gRH(Mxxz9=Ku&90%P<-?YZ=?5dD>lzrmed8aTY=_P#t?$Jaj! zd~ph%Y2R-_`qP<`$?!5=8>?bK9opt!bix*p_h**Pr}oZo+QqlEmfTC$Jc^+>x8ss5 z7!B4@jXgpiZh+}3?2SS)^V3AszND)RYc$y}S!+9IjqP-Dz{_Ckv|C}bQ|&IG7of(P z<;?|d$mtO#7(autCGPt8d~E>ImhS}@McNpR3AB~jjy1(f6jrz9K5#Dp;sACd1Agn@pqe~tu3v@CD1BbtjlVg6LjKFC80<$0eWbj>&a%j2>wQ=TPR@c>OC zL9B3(JlMypC<8VoRdDUqc)T?_84&&yOZdAsq5(wkd|(x^MD^ysFY0plEIg-pA!aIW zo_cwEspMWqAHXGi>Yx+lEo9o`6cRaQUcHp!)V5vR=M=7K>ZS@R_{3GHidj{AUTgFl zJ#A_m?O*A_<(4a9e7lvO9%+iuk2;6rh?}hJx4cIT1P5Xt%n_~Tn*0aUt{h}8U_Cgn zg8L`}x+U?jVpAi#Jjew0fkG{s!J_&pgaIQf*oIT`V<+Ce92&X|19hk^CAbH*GMXuOi{Wpfo0}(Luwcr3xGyfG_Og498AEt zRRn&bDHhGeTwSiFGk(@LI35(l14F*YA2l7vH^-*d0bfF$Ks^CG|Fya!jr_Y{zRmQP zBl>6j5pYN%*r{i-LXWB#U!vSD+~uIi3jzB3r2*;2BCU6fh1L7?;+uQARv?7WW}L8H z>d_0s4I)8FbN?V{g9D1L?jUw=64FWVRej*^g~~HbG(Uk4(p3ctX3UMw19$hv*k*0l zVuUMd%ShnWBqLTZ|7J&2Czt+bS!oUc_|w1)pI#n-xKirQ!}Hi=WejXup;8^&HOxmE zC6P1yRA1lBz>gK0K4>>m?;PLB&HI>alE;F~9Pg0ZV0ptFm}RYCA<~t!8}Z4)AYg#b zTZEWmL{)s`zh3&^VYcNP{WX6=7aFa(z+(<8%kNexGj`!3{4PsR=axfTVn+K>1b_A{ zBb4U(uMqx++3v9FucZbqU)u?@)i*(WQi#jc9<%7g6l-qZv}20&_8;1CCA)k1P+aLI zkgIF4<4ONfiZf!FEN0E=DV@5%+DuLlqO}w0^~WDOAjbS#uK!FO?){z1HUK-o)eCWv*d1(3a8?Ee5?iWahBD^ONW$k0Ws_XTTTsWcKb z6?&$S_vp&V_+SlpwI#4x!0oXy_n({SYoNAfCBKgH9v{`tHM2@Y+T@0Dp4K1DZfHI3 z@M;{jCA}f4#nv)P3M1BKZQ0P;fH~)ALXHAhbHh;?3k|=~{T61iSoBu1L$%=@X#%+6asIJ3W5y_l{s!~2l2D}hT$|b+Sg|@oZ z>ligl*i|j<6pb0*pWJ6ET0i@bqsq*QxKF#X_a!NRsnsUvthnkyx-g|$0~J~QXGj0) zaT{9jF7Uv$`CYj0^-_Mf4GDts>o5^swUf1u(OQhaxR)#YJFP+DEK>y#7mT@MiMGFb zf|o6nr}+7IT}N@Uvrs1mZq|a`vK_@AaV1csddTtNEJr<*SsDIc`TV@KDFMt=^>tCL znKW31iDa#rkg0B92fCfUv+VF&z9S0;Y*y(rE5Vm89Q}}kuG|ENnh+Z{Q9Xs z)nO8I`q+Un%@okBNb-kc{<3q18qs3MpSJ7&YN%>svyG?r%{ffqd5smGD1Bqi=GRez zTHznM`!CjtY^oGB4ioyUcmFXYZD{or|CNsaYh?ej;r@Sg`Cm}Z=571$X8f0Ex${c& z{|gI^jcS}#mFSBehcDn?m;VO)%l{WZD=z7e!B;j~+2HlhZmoZLjsM8APQt@KtoaXq zH)O&;cAgF-{`AWK>7O?@Jpb)T{C&d3L zwBb_+u4LcXxt(aD(DpYoXGD*iL=wl+#?HST?Ej^*9m@p@;_knR{#R=cOq{4Ec=S;z zcMwB&8>#YtrsZ#Pp38CEQ{XdaTmR|voI+7WMm<429{BO|ngBaAGIQDBq7cK$( zQt=BFAOB*7e-edQ>_zQ01UB1tpRqZ;^Z(_&#g$k7e{uD%Bn$*q8?FkO+s=w7{Eyd} zIIda$`M%*ej-4Ajci>F*jbAi!rt$3B;W6`duzOIa zo`%K7Xqi9S@_)I#NA_b~RBA#d%UqqGB|Pg@>j0|L5*OZySK@ zklb>3CEY5~LJd25tK<_tJRjcIe|*jAw+{ij7Q!AyXoX3Mo|oN#b1M+nP9I5ivf0ohB8+Au#|wMyHM|66XwvRm z4&{QHa7t&f9cHIz@>U$rhd?YFS)G#+M=|lsX2T(GLC%;~cp#8wlo~1}P`RuguM6Oz zZ53>yVY(eAbRAL+yqEjo$ViUw8izXJ7?ApiOq@H^XSyy6Yhe=H$}M*a)Pqqte^fv!0mqz9lwlnM1Z*Y4A&i z=?KhycK+svu1mgh7-T)(s*G06yr_ns>bCf;{<3~CJi`jVJPyes@9>t-LXJ`D{f#DE zIT8o!%-k8Mw?|{#nSd2wkI8wu(`IZN)t6xgR!qaQmn}Z0h0wLo5HmDjpsfvOdkJm! zsCNcVh~%W;kZlYheyEEG`RVlSk{m8m>yT~jV%L(TcT)HycRz<$O?nFy|4=N)s52bk zFr>gqHQO#5xmr6?J71}_tWRn`OMQ9{v@!^9BbV1ZIn}RMab8pj6wNFTY5y=djIlbs z2)!!Ni*VsOZk?{SIpNW} z7cIL{5QmH{)8s$?DKAGtekPQ(A}ic=$e4Pl)}56;&IkYA(M}lf;J_XlHcZ!gaH$=b z4Z&G|j~=YHuz8tUWu69N8COswO1o8aaD;ZOGqM!e85zDZfsDp-GjhVr=E&v0l|q5r z_!4-;$gKB;S2>mIrKzjsdHmoM{LQt0uc_6SAdTYcoHw&wao&VzLrW1A_a&czh-4MV z8@OsNhwS38;jVQ~jH3I9TBPp{UhYOU!@vWHV+uhOS<1I>Uie}t|D4w1dH?Hd?+Cp; zYJ?=qCf|A+X!mNXP>^Q!WlN8_I|8RM{d74B%A~gO%D--#bVG+3@UT>S?3=a#cW;`Q{Eff5 z@TS!1ny*|(#z!L1ti}os3YM@17zJ!8vEsC%3FTILw*fW-eJZMimigQT8E8azFY@yV zcrVPJ?_3PU1RgyJO4#p?B-Fy*WtO=c0{GpIP-68}B4-_6S=jJbJ1oC~-FB&C>w+3v zDO`SH1Y!rl*Gk{l-*E-mJ1jeIRB(+*6y&l^pX=Q^rCPK4El#Yps#kp~X?jh?bPjOn zJLxZTJgptg;SvA5r;5Mi(Vg&7{%StBxXXR5<~pf8-`FkH7n1=^BFZrp56A@oeCEJI zfDR7vY1-7-oGm=4{3^k_$xJz1))9)8(1Y{@V&?eT7_0VXxeYM=>bEl>A;Fc2G z45ty+){wOazC4b&1N~KRS!r6J8JU+m11|&0x3(Y)*Dhdd78v$eG;B9?&yKvga?=nK zuxJJOd*&>M&bRz{UhSiFy*tRdiF%4>tWCG+4!k0EQ{bvb;>Bk41F@V}KQuv39#6C>$Q91rx7RM_Si7sP|{Ij^fSYA%nT z5BfMHPF(Vs%+9e?XwlfW;fnxx`&8z$>s7!p6Z%|C2|^M>+qT zidMmssG2~zvrWS-A!?Tr0l=E?T*pU{9D8sp=CA+Tq zwX!D2dJxftyP0W_B=YQf%GyVyjZgq=T|!L}D&(L>AiX*l7c*`Y)1~i%;54BrQWZOI znVw4!3f@LM^9_S%{=lJW(`NQsN(T5khh!?^33Tn>hiE%)<7r6`8`Bg>BW0#&0d}br zwedi2!fL@9?*mwc?7ylq#O?N+gU>^`u`+#x_Z^4{9yYr1lGEdtiA=QK+m8^ll@nt% z-9kmL$C7lUZ9J2;a)v+!nL0g6<^yexm&KubD)MPqxRyH2P?k1(tSYubbvjoXWC^w; zYB4K^5VQx^6)8G~(OZyoX;*~X7)DJkj3RVv-A@;XB*&>EHk=QoRy!_S&l=xp9ou7x zdrd=_=EzL4KRhq+x3g9}Xk5Y9(JanY+k#f++Hz7lCV<`0WddEcs+QDe0tN~DQ1QaOBD{q~V zq3MeQ*cr|E$t_-nx}a(VKPv!ulZ}0t0B)y61@3hsQ4@VL{|S;c(>SW2=zF))aJ#!= zj%dOB=4xGm3UObGU=4v3gA0`7xu<=-4vh>kIjk1w#RL5 zL=dyp=>Z$>>F8TG+Ww*$CRTWK^0|8a%$>(_*PU(af#4{Q@=ydns1C9RDKY`I$8RJ& zX?eg5EH5#$Qx$=ZP+#2uj;-s84&%P?dVIV5d??z79ftgBmBZqZX@vG1`*z@%u5KUa zbwAj?Pk=B zGcSrkaFrjRLpi>#vnrDVvH%2V?mo#iJKz`5WyXM_(V}GT6TaPq)+pN}Y=0T6m)MT% z07St}W}sCjt~U%uxUslE754yq&K5V}iMbDQzvtI8^J_G!PKHZV8UUnR!nk@cB}ApGP^YSwW%yW<^yhATiNqY}tPdcOEN`Iilw>5u zgMiDLIS8U<p|?zp9UOX*)f9KPGna^jfnimAf=+S*#2o1eH{6xb*cE=B8l%%8ZVAVMwGh^2gCW zeg*0zTeZ1OC4)Mk8N2fwri${8MhT1l3c*(RdJ4X-8r7F)T~-&fPWRkb-QvtW5ku^S zV7?t6X4r|dX_`Q~lVD-h2;9cMUI|8r6R|7a@~Y4+KQv4pMk1jX8H*6qqWkJFCtNLI z>ojxE5rLsX6c=QR-}M%>kILXA&#_q^Cc6u={Z_cms0NfMX9yZ8(4(H4gZS|o8hDI^ z!Vt7@aRi_Hlt(tIlIr_zt6TmOKf}a!o&lpf?%m-`P7<8{7*w z&YUt1F3A3U)+I`BC{yFrMgk;-5`{m6lJ46Ub0AvO1^b23gyM{8AD+4OvV+sfqzj_L zJ)$p$RVtO{=_+1l6fD@Ds5+S`QAITebdUhlm)+oER=IhAfOWAR+4!3{DK(CW_SJm` zmXks3=?9BFw3JD=kT;ZLyubKr3q$z1q82slwM9peKk&g7XFvGC6o8KI$jA}*yI0D` zLtI6ZGUb%W^%$wx+FOxn=hdQscH0CS15FzSa%Re6-155T(iZvYwk8xY63PQHZESe8 zt5ICL0`!U1y@S+CZ?fahP&-G4ZPO6|fR>5wA|H87?@Nv&OlAy_CdZPFKtcHR$a@%m zBA-GL2L8;16pZ?1u0I|AY`cyARSIaBmeb$to>a5%~GvC()Bex_tQMn`__1z9I2QPg&06Al( zz%jutw+|#@!0N~RU-gHMl~#s1KG+kXPLuO|IkL3OQ`(~&a_BD!tYLM$LTs_Io#g9P z)2@Yp%VN)_N_B2LOhiy}1;M60`yYTd6RP5{S0??#zU}bLudW$@vFKjaG9oh&-4l7r zK>|BVC~d4Y6Q~NyaQ$j6_Ld^IQ}!g2)-wkr_4!^JTx`T`$wAqT?OG&dAC`6e3_nUU z`NSW{vTAiCrQMDx;q>o}dga|yw*|w}Odg$nM$ZE?C7J5*7Q`-l=LdGpyhF~!8+MGB zYR&e0Y2(UH3CRNIn^r6yX-#L%W#j@I;=%QAAyf27d4wF0=a#wfVeMOs{jSWbW>9Lx2=Gwjz!-hhl zTeha%6YA`FwN#CAYm&rq^{{EPG8k$T3bi?d|;4lv#PI* zd+tXDiIE9IZ}8Mmp%42IGdvFI&4i=DvCEenvPO{fA#hLQnNGTt8H;05DMRnK;H3L} zkVk_KUfz?a>6BgA2A9U-)M`|{$VU=5Oi)z<_t3ev_V+9sx+Q~~{W&}DI+ym-`*L$t zw;_Y#mDD6?eJ~OmnM+a8!1H$3JUrMCZ24?}4rl}zfIJvZNptjWFS5KY?3UF>6~;v& zqbqtn>8W|09x2LCV+jnt40BaRl9QrBhI-k=)K;_taqS3;>A@9^%ar2V zUDc&7ch&Bs=btS`w+HBNXlKgeI@_Y(+HGi&+-@oPk0Tp~csNsI>yn6lB({*&NylBi zGZ4QqFNWs64?jGid0QZI~ZD76P?mJI&+J{fvo zJ)%Kjeby_qJDrcSgXd{6r|&0L6H`GI33jQY zv6UL|Q#7kbk?(YaXfxh44ILeD=a6!17mE&e;0HB)+p$f{JEVP^F=agHBJLrDsKhD; zDt-t>Q=TjP%JtYz=KdpMi>_5ig=-Ar)$dh7cd*IW0}UmGL9LmFf{9IAtEWdb_CvU?>%{4)UYfe$z{+buGk40tST@>hsJm& z4Zr*)3s>OuTLk*Mo5%MMSdA%H)Q)O?M@raJ)RBEoW!{oP(Unsh%j`^vVvl_P>N9kk$SAV^M zvJRm#qq99Qo13=75>06-p0Wzqlupq9Uk(+xRWtRf

X2RA07zIQv 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 diff --git a/docs/screenshots/home.webp b/docs/screenshots/home.webp index b3d9ca9bfeb52b95a98778c4843151a1a8ed7920..bfb558efa68ffa4f04f5c0ae5a1a9959b0e87309 100644 GIT binary patch literal 71550 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 SVhS6`@j`?spa4L)0000I_M)f& literal 60002 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�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 G0000Q&!ss4 diff --git a/docs/screenshots/profile.webp b/docs/screenshots/profile.webp index 88170336295716613a39040f70dd8ccde8b771cd..8b605c697b8d888a7937b7ffd37833a4ec6355b3 100644 GIT binary patch literal 31008 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®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 TtS}thMoK||H%5Tm1_1Cswjh2* literal 36726 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 Lfz%+e#sB~SP_#0h From 44440aaf12ca176d27bc7f075876e79b27c70224 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 16:51:00 +0200 Subject: [PATCH 09/31] test: wait for the latest presence cache expiry --- CHANGELOG.md | 1 + e2e/presence-worker.fixture.spec.ts | 23 +++++++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03995299..7cb44035 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch ### Development - Cold-load performance checks retain sanitized per-sample LCP, network, cache and long-task diagnostics, including on failure. Their timing limits, cold contexts and sample count are unchanged. +- Browser regressions wait for restored seen rows and the latest presence-cache expiry, including a deliberately delayed count refresh, while preserving their exact ordering, privacy and timing checks. - Local macOS builds find worker-build's cached WebAssembly optimizer. SDK wire-format and strict-CSP browser checks cover Messages; feed-ranking, reply-composer and smoothness fixtures exercise the updated UI without changing their budgets. - The attestation-key helper replaces the complete Rust key array, including multiline values, so a generated key compiles. diff --git a/e2e/presence-worker.fixture.spec.ts b/e2e/presence-worker.fixture.spec.ts index 5e32496d..0d73291c 100644 --- a/e2e/presence-worker.fixture.spec.ts +++ b/e2e/presence-worker.fixture.spec.ts @@ -46,6 +46,8 @@ let state = ""; const printed: string[] = []; /** What the stand-in node was asked. */ const asked: string[] = []; +/** A response finishes after any edge-cache write that beat requested. */ +let lastBeatAt = 0; /** A session cookie as the Worker's sign-in sets it. */ function session(fid: number) { @@ -67,7 +69,9 @@ async function beat(body: object | string, { cookie = "", origin = ORIGIN as str if (origin !== null) headers.origin = origin; if (cookie) headers.cookie = cookie; const response = await fetch(`${ORIGIN}/api/v1/presence`, { method: "POST", headers, body: typeof body === "string" ? body : JSON.stringify(body) }); - return { status: response.status, cache: response.headers.get("cache-control"), json: await response.json() }; + const json = await response.json(); + lastBeatAt = Date.now(); + return { status: response.status, cache: response.headers.get("cache-control"), json }; } /** A query on the Worker's local D1. Not run synchronously: that would @@ -133,13 +137,12 @@ test.afterAll(async () => { }); test.describe("on", () => { - /** When this location last counted. */ - let counted = 0; - /** Wait until the next beat recounts. */ + /** A public or visibility-changing beat may refresh the cached answer. + * Wait from the latest response, a safe upper bound on that cache write, + * rather than from the first count before those later beats arrived. */ const recount = async () => { - const wait = counted + RECOUNT_MS - Date.now(); + const wait = lastBeatAt + RECOUNT_MS - Date.now(); if (wait > 0) await new Promise((done) => setTimeout(done, wait)); - counted = Date.now(); }; test.beforeAll(async () => { @@ -153,7 +156,6 @@ test.describe("on", () => { const [a, b, signedIn, forged, readable] = [id(), id(), id(), id(), id()]; // The first beat counts: one here, no one named, beat again in four minutes. - counted = Date.now(); const first = await beat({ id: a, hidden: false }); expect(first.status).toBe(200); expect(first.cache).toBe("no-store"); @@ -165,7 +167,12 @@ test.describe("on", () => { // location counted a moment ago.) expect((await beat({ id: b })).status).toBe(200); // A signed-in reader, named by their session cookie. - expect((await beat({ id: signedIn }, { cookie: session(reader.fid) })).status).toBe(200); + // The public beat starts a new edge-cache window even when earlier + // beats were already counted. Keep it away from that first boundary. + await new Promise((done) => setTimeout(done, 2_000)); + const named = await beat({ id: signedIn }, { cookie: session(reader.fid) }); + expect(named.status).toBe(200); + expect(named.json.online).toBe(3); // Never by what the browser says: a fid in the beat, or the readable user cookie. expect((await beat({ id: forged, fid: 7, username: "forged" })).status).toBe(200); const userCookie = `__Host-allthing-user=${encodeURIComponent(JSON.stringify({ fid: 8, username: "claimed" }))}`; From 06e21bbf7cc7f63230215ffc33f905a5d7d8b422 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 17:02:16 +0200 Subject: [PATCH 10/31] fix(feed): retain bounded source clock skew during ingest --- CHANGELOG.md | 2 +- crates/allthing-core/src/index.rs | 36 ++++++++++--- crates/allthing-core/src/latest.rs | 17 ++++--- crates/allthing-core/src/ranking.rs | 21 +++++++- crates/allthing-data/src/pages.rs | 78 ++++++++++++++++++++++++++--- docs/ARCHITECTURE.md | 2 +- docs/BUDGET.md | 2 +- 7 files changed, 131 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cb44035..76d96c8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch ### Fixed -- Future-dated casts cannot outrank the present in For you or Following, including All time and early paint. Cached newest-cast payloads and index rankings exclude future timestamps before selecting their visible rows. +- Future-dated casts cannot outrank the present in For you or Following, including All time and early paint. Cached newest-cast payloads and index rankings exclude future timestamps before selecting their visible rows. Ingest retains up to five seconds of source clock skew in the existing buffer; implausible dates are discarded, and retained rows appear only when their timestamp is reached. - A directly opened mini app post follows Show mini app casts immediately in both directions, without a reload or refetch. Hiding it removes its body and embedded content while retaining its Open in Farcaster link; ordinary posts keep their content. - Short time ranges include newly posted casts even while Hypersnap's trending list lags behind. Every sort keeps the chosen range, and the end-of-range note appears below the list without moving cards down. diff --git a/crates/allthing-core/src/index.rs b/crates/allthing-core/src/index.rs index 7fdec1fb..48bed0f6 100644 --- a/crates/allthing-core/src/index.rs +++ b/crates/allthing-core/src/index.rs @@ -19,7 +19,7 @@ use serde::{Deserialize, Serialize}; use crate::model::Cast; use crate::normalize::{self, RawCast}; -use crate::ranking::{RECAST_WEIGHT, TrendingWindow, points}; +use crate::ranking::{RECAST_WEIGHT, TrendingWindow, may_ingest_timestamp, points}; use crate::time::parse_rfc3339; const DAY: i64 = 86_400; @@ -166,7 +166,7 @@ pub fn candidates(raw: &[RawCast], metas: &[RankingMeta], now: i64) -> Vec + RECAST_WEIGHT * count(reactions.and_then(|x| x.recasts_count)) + count(r.replies.as_ref().and_then(|x| x.count)); let ts = r.timestamp.as_deref().and_then(parse_rfc3339).unwrap_or(0); - TrendingWindow::All.holds(ts, now) && points >= floor(metas, ts, now).min(NOTABLE_POINTS) + may_ingest_timestamp(ts, now) && points >= floor(metas, ts, now).min(NOTABLE_POINTS) }) .map(normalize::cast) .collect() @@ -179,9 +179,7 @@ pub fn worth_indexing(casts: &[Cast], metas: &[RankingMeta], now: i64) -> Vec= floor(metas, c.ts, now) - }) + .filter(|c| !c.is_reply() && !c.spam && may_ingest_timestamp(c.ts, now) && points(c) >= floor(metas, c.ts, now)) .filter(|c| seen.insert(c.hash.as_str())) .map(|c| Entry(c.hash.clone(), c.ts, points(c))) .collect() @@ -505,9 +503,31 @@ mod tests { } #[test] - fn future_dated_casts_are_not_indexed_even_when_their_points_would_rank() { - let casts = vec![cast("0xfuture", 1, NOW + 1, 1_000_000), cast("0xnow", 1, NOW, 30)]; - assert_eq!(worth_indexing(&casts, &[], NOW), [Entry("0xnow".into(), NOW, 30)]); + fn only_small_clock_skew_is_worth_indexing_not_implausible_future_dates() { + let casts = vec![ + cast("0xskew", 1, NOW + 5, 30), + cast("0xfuture", 1, NOW + 6, 1_000_000), + cast("0xfar", 1, 2_893_718_638, 1_000_000), + cast("0xnow", 1, NOW, 30), + ]; + assert_eq!( + worth_indexing(&casts, &[], NOW), + [Entry("0xskew".into(), NOW + 5, 30), Entry("0xnow".into(), NOW, 30)] + ); + } + + #[test] + fn only_small_clock_skew_is_normalized_as_an_index_candidate() { + let raw: Vec = serde_json::from_str( + r#"[ + {"hash":"0xskew","timestamp":"2026-10-02T00:00:05Z","reactions":{"likes_count":30}}, + {"hash":"0xfuture","timestamp":"2026-10-02T00:00:06Z","reactions":{"likes_count":1000000}}, + {"hash":"0xfar","timestamp":"2061-09-12T00:03:58Z","reactions":{"likes_count":1000000}} + ]"#, + ) + .unwrap(); + let now = parse_rfc3339("2026-10-02T00:00:00Z").unwrap(); + assert_eq!(candidates(&raw, &[], now).iter().map(|cast| cast.hash.as_str()).collect::>(), ["0xskew"]); } #[test] diff --git a/crates/allthing-core/src/latest.rs b/crates/allthing-core/src/latest.rs index 1d41da6e..a4b6cca4 100644 --- a/crates/allthing-core/src/latest.rs +++ b/crates/allthing-core/src/latest.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; use crate::model::Cast; use crate::provenance::base64_decode; -use crate::ranking::TrendingWindow; +use crate::ranking::{TrendingWindow, may_ingest_timestamp}; /// The shards that hold users' messages (shard 0 holds none). pub const SHARDS: [u32; 2] = [1, 2]; @@ -154,15 +154,16 @@ pub fn to_hydrate(added: &[Added], listed: &[Cast], removed: &[String], limit: u } /// The newest `keep` casts of `listed` and `fresh` (newly read, so they -/// replace listed copies), without `removed` or future-dated ones. Filter before -/// truncation so an invalid future timestamp cannot take a real cast's slot. +/// replace listed copies), without `removed` or implausible future dates. A +/// five-second source skew may stay in this existing buffer; serving is stricter. +/// Reject beyond that allowance before the cut so invalid dates cannot fill it. pub fn newest(listed: Vec, fresh: Vec, removed: &[String], keep: usize, now: i64) -> Vec { let fresh_hashes: HashSet = fresh.iter().map(|c| c.hash.clone()).collect(); let mut all: Vec = fresh .into_iter() .chain(listed.into_iter().filter(|c| !fresh_hashes.contains(&c.hash))) .filter(|c| !removed.contains(&c.hash)) - .filter(|c| TrendingWindow::All.holds(c.ts, now)) + .filter(|c| may_ingest_timestamp(c.ts, now)) .collect(); all.sort_by(|a, b| b.ts.cmp(&a.ts).then_with(|| a.hash.cmp(&b.hash))); all.truncate(keep); @@ -350,10 +351,10 @@ mod tests { } #[test] - fn future_dated_fresh_and_cached_casts_cannot_take_a_newest_slot() { + fn only_small_clock_skew_can_stay_in_the_existing_newest_buffer() { let listed = vec![cast("0xoldfuture", 2_893_718_638, 999), cast("0xold", 20, 1)]; - let fresh = vec![cast("0xnewfuture", 41, 999), cast("0xnow", 40, 1)]; - let hashes: Vec<_> = newest(listed, fresh, &[], 2, 40).into_iter().map(|c| c.hash).collect(); - assert_eq!(hashes, ["0xnow", "0xold"]); + let fresh = vec![cast("0xskew", 45, 999), cast("0xnewfuture", 46, 999), cast("0xnow", 40, 1)]; + let hashes: Vec<_> = newest(listed, fresh, &[], 3, 40).into_iter().map(|c| c.hash).collect(); + assert_eq!(hashes, ["0xskew", "0xnow", "0xold"]); } } diff --git a/crates/allthing-core/src/ranking.rs b/crates/allthing-core/src/ranking.rs index e1365e14..fff5932b 100644 --- a/crates/allthing-core/src/ranking.rs +++ b/crates/allthing-core/src/ranking.rs @@ -7,6 +7,15 @@ use std::collections::BTreeSet; use crate::model::{Cast, ThreadNode}; +/// Allthing's ingest-only buffer for small source clock skew, preserving the +/// previously tested five-second case. This is not a protocol threshold and +/// never changes the strict present upper bound used when serving or drawing. +pub const INGEST_FUTURE_ALLOWANCE_SECS: i64 = 5; + +pub fn may_ingest_timestamp(ts: i64, now: i64) -> bool { + ts <= now.saturating_add(INGEST_FUTURE_ALLOWANCE_SECS) +} + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] pub enum Sort { #[default] @@ -190,7 +199,7 @@ impl TrendingWindow { /// seconds since the Unix epoch, which has no time zone). The window /// starts just after `now − span`: a cast exactly that old is out, and /// one a second newer is in. Future-dated casts are out in every range, - /// including all time; a clock ahead becomes eligible when `now` catches up. + /// including all time. A retained cast can become visible when `now` catches up. pub fn holds(self, ts: i64, now: i64) -> bool { ts <= now && self.span_secs().is_none_or(|span| ts > now - span) } @@ -523,6 +532,16 @@ mod tests { assert!(TrendingWindow::All.holds(i64::MIN / 2, 1_792_000_000)); } + #[test] + fn ingest_alone_keeps_five_seconds_of_source_skew_with_saturating_arithmetic() { + let now = 1_792_000_000; + assert!(may_ingest_timestamp(now + 5, now)); + assert!(!may_ingest_timestamp(now + 6, now)); + assert!(!may_ingest_timestamp(2_893_718_638, now)); + assert!(may_ingest_timestamp(i64::MAX, i64::MAX - 2)); + assert!(!TrendingWindow::All.holds(now + 5, now)); + } + #[test] fn a_window_is_plain_seconds_across_midnight_utc() { // 23:50 to 00:20 UTC, with the clock at 00:10: a one-hour window diff --git a/crates/allthing-data/src/pages.rs b/crates/allthing-data/src/pages.rs index 9cadbf67..c511f31b 100644 --- a/crates/allthing-data/src/pages.rs +++ b/crates/allthing-data/src/pages.rs @@ -521,7 +521,9 @@ pub async fn latest(inv: Rc, previous: Option>>) -> Resul } warm = serde_json::from_str(&stored.body).ok(); } - build_latest(&inv, warm).await + let mut payload = build_latest(&inv, warm).await?; + payload.pool.retain(|cast| TrendingWindow::All.holds(cast.ts, now_secs(&inv))); + Built::json(&payload, api::LATEST_CACHE) } /// The cron's turn: the newest casts, built on the stored copy and stored @@ -530,8 +532,10 @@ pub async fn latest(inv: Rc, previous: Option>>) -> Resul pub async fn store_latest(inv: Rc) -> Result<(), Failure> { let index = inv.index().ok_or_else(|| Failure::internal("no index to store the newest casts in"))?; let warm = stored(&inv, LATEST_SNAPSHOT).await.and_then(|s| serde_json::from_str(&s.body).ok()); - let built = build_latest(&inv, warm).await?; - let body = String::from_utf8(built.body).map_err(|e| Failure::internal(&e.to_string()))?; + // Keep the bounded ingest buffer for the cron; the public `latest` view + // excludes every future timestamp, without mutating this stored source. + let payload = build_latest(&inv, warm).await?; + let body = serde_json::to_string(&payload).map_err(|e| Failure::internal(&e.to_string()))?; if !inv.take_subrequests(1) { return Err(Failure::internal("no subrequest left to store the newest casts")); } @@ -564,7 +568,7 @@ async fn stored(inv: &Invocation, name: &'static str) -> Option { index.snapshot(name).await.ok().flatten() } -async fn build_latest(inv: &Invocation, warm: Option) -> Result { +async fn build_latest(inv: &Invocation, warm: Option) -> Result { let warm = warm.filter(|p| inv.now() - (p.meta.fetched_at as f64) < WARM_MS); let (listed, cursors, mut notes) = match warm { Some(p) => (p.pool, p.cursors, p.notes), @@ -611,7 +615,7 @@ async fn build_latest(inv: &Invocation, warm: Option) -> Result>, stored: Option>, + now_ms: Option, } /// The part of the index the newest casts use: the cron's stored copy. @@ -1581,7 +1586,7 @@ mod tests { impl Host for Hub { fn now(&self) -> f64 { - 1_800_000_000_000.0 + self.now_ms.unwrap_or(1_800_000_000_000.0) } fn fetch(&self, request: HttpRequest) -> LocalBoxFuture<'static, Result> { @@ -1761,7 +1766,7 @@ mod tests { before = payload.pool.len(); let mut future = present; future.hash = "0xfuture".into(); - future.ts = (NOW / 1000.0) as i64 + 1; + future.ts = (NOW / 1000.0) as i64 + 5; payload.pool.insert(0, future); snapshot.body = serde_json::to_string(&payload).unwrap(); } @@ -1774,6 +1779,17 @@ mod tests { assert_eq!(built.fetched_at, Some(NOW - 40_000.0)); assert_eq!(stored.reads.get(), 1); assert!(hub.requests.borrow().is_empty()); + // The source copy still holds the small skew. A later public read can + // expose it, if retained, without re-reading the event source or aging it anew. + let later = Rc::new(Hub { stored: Some(stored.clone()), now_ms: Some(NOW + 5_000.0), ..Default::default() }); + let inv = Rc::new(Invocation::new(later.clone(), 45)); + let built = latest(inv, None).now_or_never().unwrap().unwrap(); + let payload: LatestPayload = serde_json::from_slice(&built.body).unwrap(); + assert_eq!(payload.pool.len(), before + 1); + assert!(payload.pool.iter().any(|cast| cast.hash == "0xfuture")); + assert_eq!(built.fetched_at, Some(NOW - 40_000.0)); + assert_eq!(stored.reads.get(), 2, "one existing snapshot read for each public request"); + assert!(later.requests.borrow().is_empty()); } #[test] @@ -1819,6 +1835,54 @@ mod tests { assert_eq!(payload.pool.iter().map(|c| c.hash.as_str()).collect::>(), ["0xd3"]); assert_eq!(payload.cursors, [Cursor { shard: 1, event_id: 13 }, Cursor { shard: 2, event_id: 22 }]); } + + #[test] + fn only_the_crons_existing_buffer_retains_a_small_source_clock_skew() { + let now = allthing_core::time::parse_rfc3339("2026-10-02T00:00:00Z").unwrap() as f64 * 1000.0; + let stored = Rc::new(Stored::default()); + let mut hub = Hub { stored: Some(stored.clone()), now_ms: Some(now), ..Default::default() }; + hub.events.insert( + ("1".into(), "newest".into()), + page(&[ + add(12, "0xnow", 100, false), + add(13, "0xskew", 105, false), + add(14, "0xfuture", 106, false), + add(15, "0xfar", 107, false), + ]), + ); + hub.events.insert(("2".into(), "newest".into()), page(&[])); + for (hash, timestamp) in [ + ("0xnow", "2026-10-02T00:00:00Z"), + ("0xskew", "2026-10-02T00:00:05Z"), + ("0xfuture", "2026-10-02T00:00:06Z"), + ("0xfar", "2061-09-12T00:03:58Z"), + ] { + hub.casts.insert(hash.into(), raw_cast(hash, timestamp, 1)); + } + let public = build( + Rc::new(Hub { + events: hub.events.clone(), + casts: hub.casts.clone(), + now_ms: Some(now), + ..Default::default() + }), + None, + ) + .unwrap(); + assert_eq!(public.pool.iter().map(|cast| cast.hash.as_str()).collect::>(), ["0xnow"]); + + let hub = Rc::new(hub); + let inv = Rc::new(Invocation::new(hub.clone(), 45)); + store_latest(inv).now_or_never().unwrap().unwrap(); + let saved = stored.copy.borrow().clone().unwrap(); + let payload: LatestPayload = serde_json::from_str(&saved.body).unwrap(); + assert_eq!(payload.pool.iter().map(|cast| cast.hash.as_str()).collect::>(), ["0xskew", "0xnow"]); + assert_eq!(payload.cursors, [Cursor { shard: 1, event_id: 15 }]); + assert_eq!(stored.reads.get(), 1); + assert_eq!(hub.requests.borrow().iter().filter(|url| url.contains("/v1/events?")).count(), 2); + assert_eq!(hub.requests.borrow().iter().filter(|url| url.contains("/v2/farcaster/casts?")).count(), 1); + assert_eq!(saved.built, now); + } } #[cfg(test)] diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 3bf68a59..ec7d4fc6 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -157,7 +157,7 @@ Hypersnap ranks trending casts over 7 days at most, and its search ignores dates - **Storage.** `casts` holds each kept cast's hash, time and points; storing it again updates its points, and writes nothing if they haven't changed. `rankings` holds each span's top 1,000 casts as one JSON row, recomputed inside D1 by one statement, so the Worker never reads more than a page of casts. A ranking is due again a minute per 50 indexed casts after it was computed, between 5 minutes and 6 hours. `state` holds where each feed is, and the day's D1 usage. - **Limits.** The indexer estimates its D1 rows read and written and stops reading for the day at 50,000 rows written or 2,000,000 read, half of the free plan's 100,000 and 5,000,000 or less, leaving the rest to the front page. See [BUDGET.md](BUDGET.md#9-the-index-cron-and-d1). - **Reading.** `/api/v1/home?window=30d|365d|all` reads the span's ranking row, then the page's 100 casts in one bulk `casts?casts=…` call, so counts, text and media are fresh; deleted casts drop out, spam is filtered again and mini apps are marked. The payload's `index` (`IndexCoverage`) says how many casts the span was ranked from and the oldest one's date, and the page shows it under the time filter. Until a span has a ranking (a new index, or D1 not answering), the payload is the past week's trending pool without `index`, and the page says so. The static copy has no index: its menu leaves these ranges out. -- **Time windows.** A trending window holds only the casts posted within it, judged by each cast's own time against the Worker's clock, before the page is cut (`TrendingWindow::holds`, the same edges in the browser and early paint). The lower edge is exclusive and the present is inclusive: `now - span < ts <= now`. All time has no lower edge, but still excludes future timestamps. A cast from a clock ahead waits until the current time reaches it. Following and newest-cast payloads, including stored snapshots, also exclude the future, and index rankings cannot let future rows fill their slots. These checks use existing reads; the stored newest-casts fast path parses its payload to validate timestamps and serializes again only when rows are removed. Hypersnap's `time_window` has 1 hour, 6 hours, 24 hours and 7 days; it answers 12 hours with its 24-hour list, which is cut to 12 hours. A page can hold fewer casts than a full batch, when the window holds fewer: the list then ends, and the page says so ("Only 3 casts in the past 12 hours.") instead of padding it with older casts. A copy is kept no longer than its window (`api::home_cache`). +- **Time windows.** A trending window holds only the casts posted within it, judged by each cast's own time against the Worker's clock, before the page is cut (`TrendingWindow::holds`, the same edges in the browser and early paint). The lower edge is exclusive and the present is inclusive: `now - span < ts <= now`. All time has no lower edge, but still excludes future timestamps. Following and newest-cast responses, including those read from a stored snapshot, also exclude the future, and index rankings cannot let future rows fill their slots. Ingest alone allows five seconds of source clock skew (`may_ingest_timestamp`, an Allthing buffer allowance, not a protocol threshold): the existing 100-cast newest buffer and index may retain those casts, while later dates are discarded before the buffer is cut. A retained cast can become visible when the clock catches up, but overflow or advancing a filtered stateless cursor does not guarantee another chance to serve it; there is no deferred queue. These checks use existing reads; the stored newest-casts fast path parses its payload to validate timestamps and serializes again only when rows are removed, without changing the stored source or its age. Hypersnap's `time_window` has 1 hour, 6 hours, 24 hours and 7 days; it answers 12 hours with its 24-hour list, which is cut to 12 hours. A page can hold fewer casts than a full batch, when the window holds fewer: the list then ends, and the page says so ("Only 3 casts in the past 12 hours.") instead of padding it with older casts. A copy is kept no longer than its window (`api::home_cache`). - **Coverage** grows as the feeds are read back: Past month and Past year fill within hours, and All time keeps deepening for days as the queued authors' histories are read. The ranking reflects what has been indexed, which the note under the filter states. ## Daily active accounts diff --git a/docs/BUDGET.md b/docs/BUDGET.md index 6f781df9..15837e6a 100644 --- a/docs/BUDGET.md +++ b/docs/BUDGET.md @@ -71,7 +71,7 @@ Images and videos never touch the Worker, except readers' own attachments, which The front page fills the space near the end of the list even when filtering leaves a batch short or empty. It can request offsets 100 through 900, at most nine additional payloads (1,000 source casts including the first page). Each payload remains a separate cached, guarded invocation with the same 45-subrequest budget. Failed pages keep their 2, 4 and 8 second retry delays. Deep scrolling or short filtered batches can therefore cost up to ten home requests per visit; the typical capacity estimate below does not describe that worst case. -Future timestamp checks use the existing payloads and add no cache, D1 or upstream reads. Following keeps its existing decision about reading a second source page before invalid dates are removed. Serving the stored newest-casts snapshot now parses its timestamps; unchanged snapshots retain their exact bytes and only filtered snapshots are serialized again. The invocation still has the same 45-subrequest limit. +Future timestamp checks use the existing payloads and add no cache, D1 or upstream reads. Following keeps its existing decision about reading a second source page before invalid dates are removed. Ingest may retain five seconds of source clock skew in the existing newest-cast buffer and index, without a deferred queue; public responses and SQL rankings still exclude all future timestamps. Serving the stored newest-casts snapshot parses its timestamps; unchanged snapshots retain their exact bytes and only filtered snapshots are serialized again. Filtering does not mutate the stored source or reset its age. The invocation still has the same 45-subrequest limit. **Prefetching** ([PERFORMANCE.md](PERFORMANCE.md)) spends Worker requests ahead of clicks, within caps: - hover or touch on a card: one `/api/v1/cast` request, deduplicated; From e2a63a0a2e7122b64fdacafbff2668db0df382e8 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 17:02:58 +0200 Subject: [PATCH 11/31] fix: keep seen-feed cleanup after sort feedback --- CHANGELOG.md | 2 +- crates/allthing-web/src/seen.rs | 24 ++++++++++++++++++++---- e2e/seen-posts.fixture.spec.ts | 23 +++++++++++++++++++++++ 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76d96c8f..2318a8e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,9 +17,9 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch ### Fixed +- Sort tabs show their selected state before the next feed hides read cards, keeping reading-history cleanup out of the tap handler. - Future-dated casts cannot outrank the present in For you or Following, including All time and early paint. Cached newest-cast payloads and index rankings exclude future timestamps before selecting their visible rows. Ingest retains up to five seconds of source clock skew in the existing buffer; implausible dates are discarded, and retained rows appear only when their timestamp is reached. - A directly opened mini app post follows Show mini app casts immediately in both directions, without a reload or refetch. Hiding it removes its body and embedded content while retaining its Open in Farcaster link; ordinary posts keep their content. - - Short time ranges include newly posted casts even while Hypersnap's trending list lags behind. Every sort keeps the chosen range, and the end-of-range note appears below the list without moving cards down. - Following prefetches its own feed when changing sort or range, stops automatic paging at the time limit, and resumes from that cursor for a wider range. A fully seen or filtered feed offers Load more posts after ten payloads rather than reading indefinitely. - Changing accounts replaces the feed and ranking snapshot, and late answers from the previous account cannot refill its cache. Presence no longer counts an anonymous and signed-in visit twice; hiding or signing out also removes the public name from cached lists. diff --git a/crates/allthing-web/src/seen.rs b/crates/allthing-web/src/seen.rs index 3afe8f00..9973176e 100644 --- a/crates/allthing-web/src/seen.rs +++ b/crates/allthing-web/src/seen.rs @@ -184,6 +184,25 @@ impl Feed { pub fn new(enabled: bool) -> Self { let seen = use_seen(); let url = use_url(); + // A query selects a new feed generation. As with Home's ranking, + // wait for the selected tab to paint before filtering its cards: + // suppressing just-read rows can dispose most of the old list when + // progressive drawing restarts, which must not block the tap. + let query = RwSignal::new(url.with_untracked(|url| url.search().to_owned())); + Effect::new(move |_| { + if !enabled { + return; + } + let current = url.get(); + if crate::kept::is_front(current.path()) && current.search() != query.get_untracked() { + crate::components::cast::after_paint(move || { + let Some(current) = url.try_get_untracked() else { return }; + if crate::kept::is_front(current.path()) { + let _ = query.try_set(current.search().to_owned()); + } + }); + } + }); let previous = StoredValue::new(Snapshot::default()); let snapshot = Memo::new(move |_| { if !enabled { @@ -192,10 +211,7 @@ impl Feed { let before = previous.get_value(); // Home is kept, detached, while reading a post/profile. Preserve // that generation for Back, rather than shortening its scroll. - let query = url.with(|url| { - if crate::kept::is_front(url.path()) { url.search().to_owned() } else { before.key.2.clone() } - }); - let key = (seen.scope.get(), seen.epoch.get(), query); + let key = (seen.scope.get(), seen.epoch.get(), query.get()); if key == before.key { return before; } diff --git a/e2e/seen-posts.fixture.spec.ts b/e2e/seen-posts.fixture.spec.ts index 10bf2905..e099e330 100644 --- a/e2e/seen-posts.fixture.spec.ts +++ b/e2e/seen-posts.fixture.spec.ts @@ -58,6 +58,29 @@ for (const width of [1280, 390]) { }); } +test("a sort paints its selected tab before suppressing the previous generation's read cards", async ({ page }) => { + await serve(page); + await page.goto("/"); + await expect(page.locator("#app .cast-card[data-hash]")).toHaveCount(25); + await expect.poll(() => hashes(page)).toContain(hash(1)); + const firstFrame = await page.evaluate(() => new Promise<{ retained: boolean; selected: boolean; count: number }>((resolve) => { + const old = document.querySelector("#app .cast-card[data-hash]")!; + const tab = document.querySelector('#app .sort-tabs a[href*="sort=top"]')!; + // Queue this before the router handles the click. The first animation + // frame observes the tap's answer; the old list's cleanup comes later. + tab.addEventListener("click", () => requestAnimationFrame(() => resolve({ + retained: old.isConnected, + selected: document.querySelector("#app .sort-tabs a.selected")?.textContent === "top", + count: document.querySelectorAll("#app .cast-card[data-hash]").length, + })), { once: true, capture: true }); + tab.click(); + })); + expect(firstFrame).toEqual({ retained: true, selected: true, count: 25 }); + // Deferring cleanup still applies reading history to the next generation. + await expect(card(page, 1)).toHaveCount(0); + await expect(page.getByRole("button", { name: "Show seen posts", exact: true })).toBeVisible(); +}); + test("a card taller than two screens counts after a full viewport dwell, not from a sliver", async ({ page }) => { await page.setViewportSize({ width: 390, height: 844 }); // Enough preceding rows to place the card below 800 document pixels: From 32e11d4fd5ed53012f0349a84d3919401538fcd4 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 17:07:40 +0200 Subject: [PATCH 12/31] fix: keep ordinary posts mounted when mini app settings change --- CHANGELOG.md | 2 +- crates/allthing-web/src/components/quote.rs | 3 ++- crates/allthing-web/src/pages/post.rs | 7 ++++--- e2e/mini-apps.fixture.spec.ts | 6 +++++- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2318a8e5..4d9bed78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch - Sort tabs show their selected state before the next feed hides read cards, keeping reading-history cleanup out of the tap handler. - Future-dated casts cannot outrank the present in For you or Following, including All time and early paint. Cached newest-cast payloads and index rankings exclude future timestamps before selecting their visible rows. Ingest retains up to five seconds of source clock skew in the existing buffer; implausible dates are discarded, and retained rows appear only when their timestamp is reached. -- A directly opened mini app post follows Show mini app casts immediately in both directions, without a reload or refetch. Hiding it removes its body and embedded content while retaining its Open in Farcaster link; ordinary posts keep their content. +- A directly opened mini app post follows Show mini app casts immediately in both directions, without a reload or refetch. Hiding it removes its body and embedded content while retaining its Open in Farcaster link; ordinary posts and ordinary quotes keep their content and media mounted. - Short time ranges include newly posted casts even while Hypersnap's trending list lags behind. Every sort keeps the chosen range, and the end-of-range note appears below the list without moving cards down. - Following prefetches its own feed when changing sort or range, stops automatic paging at the time limit, and resumes from that cursor for a wider range. A fully seen or filtered feed offers Load more posts after ten payloads rather than reading indefinitely. - Changing accounts replaces the feed and ranking snapshot, and late answers from the previous account cannot refill its cache. Presence no longer counts an anonymous and signed-in visit twice; hiding or signing out also removes the public name from cached lists. diff --git a/crates/allthing-web/src/components/quote.rs b/crates/allthing-web/src/components/quote.rs index b5173a94..9306053d 100644 --- a/crates/allthing-web/src/components/quote.rs +++ b/crates/allthing-web/src/components/quote.rs @@ -75,7 +75,8 @@ pub fn QuoteCard( let body_cast = cast.clone(); let body = move || { let cast = &body_cast; - if cast.hidden_for(crate::miniapps::shown()) { + let shown = !cast.mini_app || crate::miniapps::shown(); + if cast.hidden_for(shown) { // No label on the cast itself: a mini app is a format, said as such. let note = if cast.spam { "Quoted cast hidden" } else { "Quoted cast hidden: mini app" }; view! {

{note}

}.into_any() diff --git a/crates/allthing-web/src/pages/post.rs b/crates/allthing-web/src/pages/post.rs index 916339e9..3609ff9c 100644 --- a/crates/allthing-web/src/pages/post.rs +++ b/crates/allthing-web/src/pages/post.rs @@ -145,12 +145,13 @@ fn PostPage() -> impl IntoView { Some(Some(Err(failure))) => view! { }.into_any(), Some(Some(Ok(Fetched { data: payload, stale, .. }))) => { let payload: Arc = payload; - // The reader's choice about mini apps: their replies and ancestors pruned - // as they chose, the page drawn again when it changes. - let show_apps = crate::miniapps::shown(); + // Only a thread with mini app replies or ancestors needs + // rebuilding when that preference changes. Ordinary posts + // keep their body, media and composer mounted. let payload = if allthing_core::thread::flatten(&payload.thread).iter().skip(1).any(|c| c.mini_app) || payload.ancestors.iter().any(|c| c.mini_app) { + let show_apps = crate::miniapps::shown(); let mut thread = payload.thread.clone(); thread.children = std::mem::take(&mut thread.children) .into_iter() diff --git a/e2e/mini-apps.fixture.spec.ts b/e2e/mini-apps.fixture.spec.ts index 2c7569ef..93fdbd0b 100644 --- a/e2e/mini-apps.fixture.spec.ts +++ b/e2e/mini-apps.fixture.spec.ts @@ -157,14 +157,18 @@ for (const size of sizes) { expect(reads, "changing Settings uses the carried post, without refetching it").toBe(1); await page.goto(`/p/${hash(1)}`); const ordinaryBody = post.locator(".post-text"); + const ordinaryQuoteBody = post.locator("blockquote.quote .quote-text"); await expect(ordinaryBody).toHaveText("An ordinary post"); + await expect(ordinaryQuoteBody).toHaveText("A plain quoted cast"); await ordinaryBody.evaluate((element) => (window as any).__ordinaryBody = element); + await ordinaryQuoteBody.evaluate((element) => (window as any).__ordinaryQuoteBody = element); for (const _ of [false, true]) { await (await settings(page)).toggle.click(); await page.keyboard.press("Escape"); await expect(ordinaryBody).toHaveText("An ordinary post"); expect(await ordinaryBody.evaluate((element) => element === (window as any).__ordinaryBody)).toBe(true); - await expect(post.locator("blockquote.quote")).toContainText("A plain quoted cast"); + await expect(ordinaryQuoteBody).toHaveText("A plain quoted cast"); + expect(await ordinaryQuoteBody.evaluate((element) => element === (window as any).__ordinaryQuoteBody)).toBe(true); await expect(post.locator(".mini-app-note, .mini-app-link")).toHaveCount(0); } expect(reads).toBe(2); From 8233b78f601f0d7ff0bc4ba83d46f2de27cbc72e Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 17:11:22 +0200 Subject: [PATCH 13/31] fix(feed): sample time after source reads complete --- CHANGELOG.md | 2 +- crates/allthing-data/src/pages.rs | 79 +++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d9bed78..8cac0c19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch ### Fixed - Sort tabs show their selected state before the next feed hides read cards, keeping reading-history cleanup out of the tap handler. -- Future-dated casts cannot outrank the present in For you or Following, including All time and early paint. Cached newest-cast payloads and index rankings exclude future timestamps before selecting their visible rows. Ingest retains up to five seconds of source clock skew in the existing buffer; implausible dates are discarded, and retained rows appear only when their timestamp is reached. +- Future-dated casts cannot outrank the present in For you or Following, including All time and early paint. Cached newest-cast payloads and index rankings exclude future timestamps before selecting their visible rows. Source reads use the clock when they finish, so casts posted while a response arrives are retained. Ingest retains up to five seconds of source clock skew in the existing buffer; implausible dates are discarded, and retained rows appear only when their timestamp is reached. - A directly opened mini app post follows Show mini app casts immediately in both directions, without a reload or refetch. Hiding it removes its body and embedded content while retaining its Open in Farcaster link; ordinary posts and ordinary quotes keep their content and media mounted. - Short time ranges include newly posted casts even while Hypersnap's trending list lags behind. Every sort keeps the chosen range, and the end-of-range note appears below the list without moving cards down. - Following prefetches its own feed when changing sort or range, stops automatic paging at the time limit, and resumes from that cursor for a wider range. A fully seen or filtered feed offers Load more posts after ten payloads rather than reading indefinitely. diff --git a/crates/allthing-data/src/pages.rs b/crates/allthing-data/src/pages.rs index c511f31b..7c9cb785 100644 --- a/crates/allthing-data/src/pages.rs +++ b/crates/allthing-data/src/pages.rs @@ -337,14 +337,13 @@ pub async fn home( // the poll's counts. let counted = async { if offset == 0 { apps_24h(&inv).await } else { None } }; let polled = async { if offset == 0 { poll_counts(&inv).await } else { None } }; - let now = now_secs(&inv); if let Some(span) = Span::of(window) && let Some(ranking) = ranking(&inv, span).await { let hashes = ranking.page(offset as usize, POOL_SIZE as usize); let (ranked, counted, poll) = join3(ranked_casts(&inv, &hashes), counted, polled).await; let (raw, casts) = ranked?; - let casts = within(window, now, casts); + let casts = within(window, now_secs(&inv), casts); let pool = drop_hidden(&inv, casts, &mut notes, &known_links, true).await; let quoted = annotate_listing(&inv, &mut notes, &pool, ORIGIN_AUTHORS, &known_links).await; notes.keep_users(read_cards(&raw, quoted), listed_accounts(&pool, ¬es.quotes)); @@ -366,6 +365,9 @@ pub async fn home( let ((trending, newest), counted, poll) = join3(join(hypersnap::trending_casts(&inv, POOL_SIZE, offset, shown), newest), counted, polled).await; let raw = trending.map_err(Failure::upstream)?; + // A source read can include casts posted after this request began. + // Judge both edges at its completion, not before awaiting the response. + let now = now_secs(&inv); // Hypersnap's list can hold casts older than the window (its 12-hour // list is its 24-hour one), so only those posted within it are kept, // before the page is cut. A page short of casts is not topped up with @@ -406,7 +408,6 @@ pub async fn following( let first = cursor.is_none(); let mut notes = carried(previous.as_deref().map(Vec::as_slice)); let known_links = std::mem::take(&mut notes.links); - let now = now_secs(&inv); let top_level = |raw: &[RawCast]| raw.iter().map(normalize::cast).filter(|c| !c.is_reply()).collect::>(); let (mut raw, mut next) = hypersnap::following_feed(&inv, fid, cursor.as_deref()).await.map_err(Failure::upstream)?; @@ -420,7 +421,9 @@ pub async fn following( } // Keep the existing page-read decision: validation must not fetch another // upstream page merely to replace rows with invalid future timestamps. - let theirs = within(TrendingWindow::All, now, theirs); + // Use the current clock after both reads: otherwise an actually present + // cast created during I/O could be dropped while its cursor advances. + let theirs = within(TrendingWindow::All, now_secs(&inv), theirs); let pool = drop_hidden(&inv, theirs, &mut notes, &known_links, true).await; let quoted = annotate_listing(&inv, &mut notes, &pool, ORIGIN_AUTHORS, &known_links).await; notes.keep_users(read_cards(&raw, quoted), listed_accounts(&pool, ¬es.quotes)); @@ -2489,6 +2492,7 @@ mod indexed_home_tests { /// Hypersnap's trending list of casts posted at fixed times, and no index. struct Trending { casts: Vec<(&'static str, &'static str)>, + next: Option<&'static str>, requests: RefCell>, } @@ -2510,7 +2514,7 @@ mod indexed_home_tests { json!({ "hash": hash, "author": { "fid": 2, "username": "two" }, "text": "words", "timestamp": timestamp }) }) .collect(); - json!({ "casts": casts }) + json!({ "casts": casts, "next": { "cursor": self.next } }) } else { json!({}) }; @@ -2524,6 +2528,69 @@ mod indexed_home_tests { } } + /// Two seconds pass while the source response arrives, including a cast + /// written during the read and one still a second ahead at its end. + struct Advancing { + feed: Trending, + now: Rc>, + } + + impl Advancing { + fn new() -> Rc { + Rc::new(Self { + feed: Trending { + casts: vec![ + ("0xduring", "2026-10-14T17:46:41Z"), + ("0xfuture", "2026-10-14T17:46:43Z"), + ("0xaged", "2026-10-14T16:46:41Z"), + ], + next: Some("42"), + requests: RefCell::new(Vec::new()), + }, + now: Rc::new(std::cell::Cell::new(NOW_MS)), + }) + } + } + + impl Host for Advancing { + fn now(&self) -> f64 { + self.now.get() + } + + fn spawn(&self, _: LocalBoxFuture<'static, ()>) {} + + fn fetch(&self, request: HttpRequest) -> LocalBoxFuture<'static, Result> { + let read = self.feed.fetch(request); + let now = self.now.clone(); + async move { + let result = read.await; + now.set(NOW_MS + 2_000.0); + result + } + .boxed_local() + } + } + + #[test] + fn home_filters_at_the_time_the_source_read_completes() { + let host = Advancing::new(); + // The one-hour window advances too: 0xaged was inside it when the + // request began, but is outside when the source response arrives. + assert_eq!(hashes(&build(&host, 0, TrendingWindow::Hour)), ["0xduring"]); + assert_eq!(host.feed.requests.borrow().iter().filter(|url| url.contains("/feed/trending?")).count(), 1); + } + + #[test] + fn following_keeps_casts_created_while_its_source_read_is_in_flight() { + let host = Advancing::new(); + let inv = Rc::new(Invocation::new(host.clone(), 45)); + let built = following(inv, 7, Some("later".into()), None).now_or_never().unwrap().unwrap(); + let payload: FollowingPayload = serde_json::from_slice(&built.body).unwrap(); + assert_eq!(payload.pool.iter().map(|cast| cast.hash.as_str()).collect::>(), ["0xduring", "0xaged"]); + assert_eq!(payload.next.as_deref(), Some("42")); + assert_eq!(host.feed.requests.borrow().iter().filter(|url| url.contains("/feed/following?")).count(), 1); + } + #[test] fn each_window_keeps_only_the_casts_posted_within_it() { // NOW_MS is 14 October 2026, 17:46:40 UTC: 30 minutes, 2 hours, 5 hours and 3 days before. @@ -2536,6 +2603,7 @@ mod indexed_home_tests { ("0xf1", "2026-10-14T17:46:41Z"), ("0xf2", "2061-09-12T00:03:58Z"), ], + next: None, requests: RefCell::new(Vec::new()), }); let shown = |window| build(&host, 0, window).pool.into_iter().map(|cast| cast.hash).collect::>(); @@ -2562,6 +2630,7 @@ mod indexed_home_tests { ("0xfuture", "2026-10-14T17:46:41Z"), ("0xfar", "2061-09-12T00:03:58Z"), ], + next: None, requests: RefCell::new(Vec::new()), }); let inv = Rc::new(Invocation::new(host.clone(), 45)); From 9d3d2ce4ea77bd8e5613f1bd3024903eee2f4878 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 17:18:16 +0200 Subject: [PATCH 14/31] ci: retain cold-load diagnostics after every performance run --- .github/workflows/ci.yml | 10 ++++++++++ CHANGELOG.md | 2 +- docs/PERFORMANCE.md | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0702a7ac..c550e988 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -90,6 +90,16 @@ jobs: - run: npx playwright test e2e/perf.spec.ts env: E2E_BASE_URL: https://allthing.social + - name: Retain performance diagnostics + if: always() + uses: actions/upload-artifact@v6 + with: + name: playwright-performance + path: | + playwright-report/ + test-results/ + if-no-files-found: ignore + retention-days: 7 speed: # The speed report (docs/PERFORMANCE.md#speed-report): load times of the diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cac0c19..2089bb10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,7 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch ### Development -- Cold-load performance checks retain sanitized per-sample LCP, network, cache and long-task diagnostics, including on failure. Their timing limits, cold contexts and sample count are unchanged. +- Cold-load performance checks retain sanitized per-sample LCP, network, cache and long-task diagnostics, including on failure, in a seven-day Actions artifact. Their timing limits, cold contexts and sample count are unchanged. - Browser regressions wait for restored seen rows and the latest presence-cache expiry, including a deliberately delayed count refresh, while preserving their exact ordering, privacy and timing checks. - Local macOS builds find worker-build's cached WebAssembly optimizer. SDK wire-format and strict-CSP browser checks cover Messages; feed-ranking, reply-composer and smoothness fixtures exercise the updated UI without changing their budgets. - The attestation-key helper replaces the complete Rust key array, including multiline values, so a generated key compiles. diff --git a/docs/PERFORMANCE.md b/docs/PERFORMANCE.md index 9a92189a..29e9f0a1 100644 --- a/docs/PERFORMANCE.md +++ b/docs/PERFORMANCE.md @@ -15,7 +15,7 @@ Navigation should feel instant: a post opens as soon as it is clicked, the feed The CI `perf` job runs `e2e/perf.spec.ts` against https://allthing.social after every push to `main` (and on demand through `workflow_dispatch`). Before measuring, it waits for `/version` to report the checked-out commit (the triggering commit for a push, or current `main` for a manual run), or a later commit on `main` that includes it. Workers Builds skips a commit that a newer push supersedes: of five merges made within 33 seconds on 19 October 2026 it built the first and the last, so a commit can be live only as part of a later one, which the job tells from the repository's history. It polls every 10 seconds for at most 30 minutes, aborts an individual version read after five seconds, and fails without benchmarking if that release never arrives. Workers Builds takes 6 to 16 minutes from a push until the commit is live, and about 25 when a second merge queues behind the first: the five-minute wait it replaced gave up 21 seconds before #144 went live on 19 October 2026, and from its introduction (#133) the job failed on every push to `main` it ran for, without measuring anything. This keeps a pending deployment from passing the budget with the previous release's results. -Each cold-home sample logs its first-card and LCP times, the LCP element and image dimensions/loading hints, navigation and resource phases, cache/Server-Timing metadata, and main-thread long tasks. The JSON attachment `home-lcp-diagnostics.json` is retained even when readiness or the budget fails. URLs retain only origin and pathname; credentials, query strings, fragments and Server-Timing descriptions are omitted. Cross-origin timing phases can be zero when the image host sends no Timing-Allow-Origin header. These observations add no warm-up fetch, wait, cache override or resource priority change: the same three cold contexts and 1.5-second median budget apply. +Each cold-home sample logs its first-card and LCP times, the LCP element and image dimensions/loading hints, navigation and resource phases, cache/Server-Timing metadata, and main-thread long tasks. The JSON attachment `home-lcp-diagnostics.json` is retained in the `playwright-performance` Actions artifact for seven days, even when readiness or the budget fails. URLs retain only origin and pathname; credentials, query strings, fragments and Server-Timing descriptions are omitted. Cross-origin timing phases can be zero when the image host sends no Timing-Allow-Origin header. These observations add no warm-up fetch, wait, cache override or resource priority change: the same three cold contexts and 1.5-second median budget apply. ## Smoothness From e8d8480e5e413387fe602a4d073b9ab6f49c103d Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:10:33 +0200 Subject: [PATCH 15/31] test: keep leaning fixture timestamps in the past --- e2e/favorites.fixture.spec.ts | 3 ++- e2e/show-less.fixture.spec.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/e2e/favorites.fixture.spec.ts b/e2e/favorites.fixture.spec.ts index becb203e..08dfe255 100644 --- a/e2e/favorites.fixture.spec.ts +++ b/e2e/favorites.fixture.spec.ts @@ -14,7 +14,8 @@ import { NOW } from "./fixture-time"; test.skip(Boolean(process.env.E2E_PAGES), "uses the Worker API contract"); const meta = { backend: "hypersnap", fetched_at: Date.now() }; -const ts = (NOW - 19); +// Leave room for Newest below: every fixture cast is in the past 24 hours. +const ts = NOW - 3 * 3600; const hex = (n: number) => `0x${n.toString(16).padStart(40, "0")}`; const person = (fid: number, username: string) => ({ fid, username, display_name: username[0].toUpperCase() + username.slice(1), follower_count: 10, following_count: 5, bio: "" }); const ann = person(1, "ann"); diff --git a/e2e/show-less.fixture.spec.ts b/e2e/show-less.fixture.spec.ts index 8b5482af..3b5f36cd 100644 --- a/e2e/show-less.fixture.spec.ts +++ b/e2e/show-less.fixture.spec.ts @@ -16,7 +16,8 @@ import { NOW } from "./fixture-time"; test.skip(Boolean(process.env.E2E_PAGES), "uses the Worker API contract"); const meta = { backend: "hypersnap", fetched_at: Date.now() }; -const ts = (NOW - 19); +// Leave room for Newest below: every fixture cast is in the past 24 hours. +const ts = NOW - 3 * 3600; const hex = (n: number) => `0x${n.toString(16).padStart(40, "0")}`; const person = (fid: number, username: string) => ({ fid, username, display_name: username[0].toUpperCase() + username.slice(1), follower_count: 10, following_count: 5, bio: "" }); const ann = person(1, "ann"); From aa988a4cd29803508150c04ef9d387be583c00a4 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:11:14 +0200 Subject: [PATCH 16/31] test(feed): keep pagination fixtures inside the past day --- e2e/feed-state.fixture.spec.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/e2e/feed-state.fixture.spec.ts b/e2e/feed-state.fixture.spec.ts index 68f513cf..cd904f9e 100644 --- a/e2e/feed-state.fixture.spec.ts +++ b/e2e/feed-state.fixture.spec.ts @@ -2,14 +2,14 @@ import { expect, test } from "@playwright/test"; test.skip(Boolean(process.env.E2E_PAGES), "uses the Worker API contract"); -const cast = (id: number, likes: number, time: number) => ({ +const cast = (id: number, likes: number, ageHours: number) => ({ hash: `0x${id.toString(16).padStart(40, "0")}`, author: { fid: 1, username: "fixture" }, - text: `Feed fixture ${id}`, ts: Math.floor(Date.now() / 1000) - 3600 + time, likes, + text: `Feed fixture ${id}`, ts: Math.floor(Date.now() / 1000) - ageHours * 3600, likes, }); // Hours apart, so hot (which counts age) and top order each page differently. Their times -// are relative to now: the page keeps only casts inside its window, and the day is the default. -const first = [cast(1, 20, 100), cast(2, 5, 100_000)]; -const next = [cast(3, 10, 200_000), cast(4, 30, 200)]; +// are all in the past and inside the default day window. +const first = [cast(1, 20, 20), cast(2, 5, 1)]; +const next = [cast(3, 10, 2), cast(4, 30, 19)]; const meta = { backend: "hypersnap", fetched_at: Date.now() }; test.beforeEach(async ({ page }) => { From 09a10ad18c92c9a5c79b624a57cc066fe9d1a6b5 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:14:53 +0200 Subject: [PATCH 17/31] test(dau): align feed timestamps with the pinned page clock --- e2e/dau.fixture.spec.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/e2e/dau.fixture.spec.ts b/e2e/dau.fixture.spec.ts index 6a8a5db4..4f8e2a23 100644 --- a/e2e/dau.fixture.spec.ts +++ b/e2e/dau.fixture.spec.ts @@ -1,6 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0-or-later import { expect, test, type Browser, type Locator, type Page, type TestInfo } from "@playwright/test"; -import { NOW } from "./fixture-time"; /* * /dau: Farcaster's daily active accounts as the cron counts them, laid out @@ -388,7 +387,9 @@ test.describe("with the Worker", () => { test("a client card links to the page, which the app opens without a reload", async ({ page }) => { await serve(page, payload()); const hash = (i: number) => `0x${(i + 1).toString(16).padStart(40, "0")}`; - const pool = Array.from({ length: 25 }, (_, i) => ({ hash: hash(i), author: { fid: 1, username: "fixture" }, text: `DAU link fixture ${i}`, ts: (NOW - 19) - i })); + // `serve` pins this browser to noon. Process time can be later, which + // would make every row future-dated and correctly remove the app legend. + const pool = Array.from({ length: 25 }, (_, i) => ({ hash: hash(i), author: { fid: 1, username: "fixture" }, text: `DAU link fixture ${i}`, ts: now - 19 - i })); const origins = Object.fromEntries(pool.map((c) => [c.hash, { signer: "0x01", app_fid: 9152 }])); await page.route("**/api/v1/home**", (route) => route.fulfill({ json: { pool, notes: { origins, apps: { "9152": { fid: 9152, username: "warpcast", display_name: "Warpcast" } } }, meta: payload().meta, apps_24h: payload().apps_24h }, From cd7c4ec4c874bf7ead140a99806ba75ba0783cb0 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:17:59 +0200 Subject: [PATCH 18/31] docs: record realistic browser fixture clocks --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2089bb10..c0476efb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,7 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch ### Development - Cold-load performance checks retain sanitized per-sample LCP, network, cache and long-task diagnostics, including on failure, in a seven-day Actions artifact. Their timing limits, cold contexts and sample count are unchanged. -- Browser regressions wait for restored seen rows and the latest presence-cache expiry, including a deliberately delayed count refresh, while preserving their exact ordering, privacy and timing checks. +- Browser regressions use past timestamps relative to the page’s own clock, wait for restored seen rows and the latest presence-cache expiry, and preserve their ordering, privacy, navigation and timing checks, including a deliberately delayed count refresh. - Local macOS builds find worker-build's cached WebAssembly optimizer. SDK wire-format and strict-CSP browser checks cover Messages; feed-ranking, reply-composer and smoothness fixtures exercise the updated UI without changing their budgets. - The attestation-key helper replaces the complete Rust key array, including multiline values, so a generated key compiles. From 88eabe448b11a4fe2e34277b4677a64b9d02ebbe Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:23:16 +0200 Subject: [PATCH 19/31] test(boot): distinguish the main module from idle splits --- e2e/boot-recovery.fixture.spec.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/e2e/boot-recovery.fixture.spec.ts b/e2e/boot-recovery.fixture.spec.ts index 5006788f..6944db13 100644 --- a/e2e/boot-recovery.fixture.spec.ts +++ b/e2e/boot-recovery.fixture.spec.ts @@ -67,13 +67,19 @@ for (const width of [1280, 390]) { const modules: { path: string, status: number, type: string | undefined }[] = []; page.on("response", (response) => { const path = new URL(response.url()).pathname; - if (path.endsWith(".wasm")) modules.push({ path, status: response.status(), type: response.headers()["content-type"] }); + // As in the fallback case, count exactly one main module, including + // any unexpected /assets fallback. Idle split/shared modules are separate. + if (/\/(?:assets|wasm)\/allthing-[0-9a-f]+\.wasm$/.test(path)) modules.push({ path, status: response.status(), type: response.headers()["content-type"] }); }); await page.route("**/api/v1/**", (route) => route.fulfill({ json: { pool: [], meta: { backend: "hypersnap", fetched_at: Date.now() }, } })); + // Exercise the ordering where valid idle modules finish before the main + // module assertions, rather than relying on the header appearing first. + const idlePoll = page.waitForResponse((response) => /\/split_poll\.wasm$/.test(new URL(response.url()).pathname)); await page.goto("/"); await expect(page.getByRole("combobox", { name: "Search casts, people and channels", exact: true })).toBeVisible(); + expect((await idlePoll).status()).toBe(200); expect(modules).toHaveLength(1); expect(modules[0].path).toMatch(/^\/wasm\/allthing-[0-9a-f]+\.wasm$/); expect(modules[0].status).toBe(200); From fb817f367b52db11ccf8ad424f245257cb885e01 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:29:25 +0200 Subject: [PATCH 20/31] test: show read posts before comparing feed rankings --- e2e/favorites.fixture.spec.ts | 2 ++ e2e/show-less.fixture.spec.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/e2e/favorites.fixture.spec.ts b/e2e/favorites.fixture.spec.ts index 08dfe255..74b8da8d 100644 --- a/e2e/favorites.fixture.spec.ts +++ b/e2e/favorites.fixture.spec.ts @@ -1,6 +1,7 @@ // SPDX-License-Identifier: AGPL-3.0-or-later import { expect, test, type Page } from "@playwright/test"; import { signIn } from "./helpers/farcaster"; +import { showSeenPosts } from "./helpers/app"; import { NOW } from "./fixture-time"; /* @@ -50,6 +51,7 @@ const order = (page: Page) => async function feed(page: Page, path: string, expected: string[]) { await page.goto(path); + await showSeenPosts(page); await expect(page.locator(".cast-card:not(.skeleton)").first()).toBeVisible(); await expect.poll(() => order(page)).toEqual(expected); } diff --git a/e2e/show-less.fixture.spec.ts b/e2e/show-less.fixture.spec.ts index 3b5f36cd..53a804eb 100644 --- a/e2e/show-less.fixture.spec.ts +++ b/e2e/show-less.fixture.spec.ts @@ -1,6 +1,7 @@ // SPDX-License-Identifier: AGPL-3.0-or-later import { expect, test, type Page } from "@playwright/test"; import { signIn } from "./helpers/farcaster"; +import { showSeenPosts } from "./helpers/app"; import { NOW } from "./fixture-time"; /* @@ -52,6 +53,7 @@ const order = (page: Page) => async function feed(page: Page, path: string, expected: string[]) { await page.goto(path); + await showSeenPosts(page); await expect(page.locator(".cast-card:not(.skeleton)").first()).toBeVisible(); await expect.poll(() => order(page)).toEqual(expected); } From 9dff65f3734f823befd426298019ac87dcd085f2 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:32:42 +0200 Subject: [PATCH 21/31] test(feed): wait for the latest source when checking time ranges --- e2e/time-filter.fixture.spec.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/e2e/time-filter.fixture.spec.ts b/e2e/time-filter.fixture.spec.ts index bef99b9d..fca8d378 100644 --- a/e2e/time-filter.fixture.spec.ts +++ b/e2e/time-filter.fixture.spec.ts @@ -40,6 +40,14 @@ async function serve(page: Page, { index = true } = {}) { const coverage = indexed.includes(window) ? { index: { casts: 12345, since, ranked_at: Date.now() } } : {}; return route.fulfill({ json: { pool: offset ? [] : pool(window), meta, ...coverage } }); }); + await page.route("**/api/v1/latest", async (route) => { + calls.push("/api/v1/latest"); + // New reads its own source. Keep it delayed and distinguishable from + // the previous trending rows, so carried controls cannot pass the test. + await new Promise((done) => setTimeout(done, 100)); + const newest = pool("7d").map((cast, i) => ({ ...cast, hash: `0x${"7".repeat(39)}${i}`, text: `Newest cast ${i}` })); + return route.fulfill({ json: { pool: newest, notes: {}, cursors: [], meta } }); + }); return calls; } @@ -94,6 +102,11 @@ test("the time filter picks the window and is kept in the URL", async ({ page }) await page.getByRole("navigation", { name: "Sort", exact: true }).getByRole("link", { name: "new", exact: true }).click(); await expect(page).toHaveURL(/[?&]t=week/); await expect(page).toHaveURL(/[?&]sort=new/); + // Wait for New's own payload, rather than checking the carried range + // before an unhandled source response can replace the previous view. + await expect(cards.first()).toContainText("Newest cast"); + await expect(cards).toHaveCount(3); + expect(calls).toContain("/api/v1/latest"); await expect(range).toBeVisible(); await expect(range).toHaveValue("week"); }); From a8f9fcd2bee54cc8e3987bf710cab035e973c2bb Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:33:37 +0200 Subject: [PATCH 22/31] docs: record browser readiness checks --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0476efb..89f018cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch - Cold-load performance checks retain sanitized per-sample LCP, network, cache and long-task diagnostics, including on failure, in a seven-day Actions artifact. Their timing limits, cold contexts and sample count are unchanged. - Browser regressions use past timestamps relative to the page’s own clock, wait for restored seen rows and the latest presence-cache expiry, and preserve their ordering, privacy, navigation and timing checks, including a deliberately delayed count refresh. +- Startup checks distinguish the main WebAssembly module from idle-loaded parts, and range navigation waits for the actual New feed response. - Local macOS builds find worker-build's cached WebAssembly optimizer. SDK wire-format and strict-CSP browser checks cover Messages; feed-ranking, reply-composer and smoothness fixtures exercise the updated UI without changing their budgets. - The attestation-key helper replaces the complete Rust key array, including multiline values, so a generated key compiles. From 39f1599d94b6eece1779acd2bc96b9f9b504289c Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 19:20:40 +0200 Subject: [PATCH 23/31] test: assert deployment-specific write readiness --- README.md | 2 +- docs/RELEASING.md | 2 +- e2e/like-recast.fixture.spec.ts | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bae3a773..4d88b37e 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ bash scripts/check.sh # version, CSP hashes, changelog lin npx playwright install chromium # once npx playwright test '\.fixture\.spec\.ts$' # deterministic browser regressions, as CI runs them npx playwright test # everything, including live Farcaster data -E2E_BASE_URL=https://allthing.social npx playwright test # against production +E2E_BASE_URL=https://allthing.social E2E_EXPECT_WRITES_READY=true npx playwright test # production bash scripts/build-pages.sh && E2E_PAGES=1 npx playwright test # the static copy ``` diff --git a/docs/RELEASING.md b/docs/RELEASING.md index df5b083b..88a1ae3c 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -54,7 +54,7 @@ Scopes are optional, for example `feat(profile): …`, `fix(worker): …` or `pe ```sh gh release create vX.Y.Z --title "Allthing X.Y.Z" --notes-file <(awk '/^## \[X.Y.Z\]/{f=1;next} /^## \[/{f=0} f' CHANGELOG.md) ``` -6. Workers Builds deploys the merge. Check that `https://allthing.social/version` reports `X.Y.Z` and the merge commit. Then run `E2E_BASE_URL=https://allthing.social npx playwright test`. +6. Workers Builds deploys the merge. Check that `https://allthing.social/version` reports `X.Y.Z` and the merge commit. Then run `E2E_BASE_URL=https://allthing.social E2E_EXPECT_WRITES_READY=true npx playwright test`. The readiness contract defaults to `false` for local development without a custody secret; deployments that endorse keys set it explicitly to `true` (`true` and `false` are the only accepted values). ## Hotfixes diff --git a/e2e/like-recast.fixture.spec.ts b/e2e/like-recast.fixture.spec.ts index dbff18e4..b00b3d7c 100644 --- a/e2e/like-recast.fixture.spec.ts +++ b/e2e/like-recast.fixture.spec.ts @@ -444,6 +444,10 @@ test("an approval from another account is refused, and signing out forgets the k }); test("the real Worker endorses keys only for a session, from Allthing, and draws only Farcaster's links", async ({ request, baseURL }) => { + // Development has no custody secret. A deployment that endorses keys + // explicitly opts into the opposite exact readiness contract. + const readiness = process.env.E2E_EXPECT_WRITES_READY ?? "false"; + expect(readiness, "E2E_EXPECT_WRITES_READY must be true or false").toMatch(/^(true|false)$/); const writes = await request.get("/api/v1/signer"); expect(writes.status()).toBe(401); expect(writes.headers()["cache-control"]).toBe("no-store"); @@ -477,5 +481,5 @@ test("the real Worker endorses keys only for a session, from Allthing, and draws expect(refused.status(), url).toBe(400); } const status = await (await request.get("/api/v1/status")).json(); - expect(status.writes).toEqual({ ready: false }); + expect(status.writes).toEqual({ ready: readiness === "true" }); }); From 795e88d36d538a27b1fe14737e3a5b08e24401f5 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 19:28:55 +0200 Subject: [PATCH 24/31] test: verify complete enabled-write status shape --- e2e/like-recast.fixture.spec.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/e2e/like-recast.fixture.spec.ts b/e2e/like-recast.fixture.spec.ts index b00b3d7c..2346f8d9 100644 --- a/e2e/like-recast.fixture.spec.ts +++ b/e2e/like-recast.fixture.spec.ts @@ -481,5 +481,10 @@ test("the real Worker endorses keys only for a session, from Allthing, and draws expect(refused.status(), url).toBe(400); } const status = await (await request.get("/api/v1/status")).json(); - expect(status.writes).toEqual({ ready: readiness === "true" }); + expect(status.writes).toEqual(readiness === "true" ? { + ready: true, + app_fid: 3356318, + address: expect.stringMatching(/^0x[0-9a-fA-F]{40}$/), + sponsored: expect.any(Boolean), + } : { ready: false }); }); From 8fcbd4fed3833b47f67facb800086746238280f6 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 19:34:13 +0200 Subject: [PATCH 25/31] fix(emoji): align groups before progressive drawing completes --- CHANGELOG.md | 1 + .../src/components/emoji_picker.rs | 11 +++++-- e2e/emoji-picker.fixture.spec.ts | 30 +++++++++++++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89f018cf..7486685f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch ### Fixed +- Choosing an emoji group while the picker is still drawing reaches its heading on the first click, including a group at the temporary bottom of the list. - Sort tabs show their selected state before the next feed hides read cards, keeping reading-history cleanup out of the tap handler. - Future-dated casts cannot outrank the present in For you or Following, including All time and early paint. Cached newest-cast payloads and index rankings exclude future timestamps before selecting their visible rows. Source reads use the clock when they finish, so casts posted while a response arrives are retained. Ingest retains up to five seconds of source clock skew in the existing buffer; implausible dates are discarded, and retained rows appear only when their timestamp is reached. - A directly opened mini app post follows Show mini app casts immediately in both directions, without a reload or refetch. Hiding it removes its body and embedded content while retaining its Open in Farcaster link; ordinary posts and ordinary quotes keep their content and media mounted. diff --git a/crates/allthing-web/src/components/emoji_picker.rs b/crates/allthing-web/src/components/emoji_picker.rs index aab4eda3..ef54255b 100644 --- a/crates/allthing-web/src/components/emoji_picker.rs +++ b/crates/allthing-web/src/components/emoji_picker.rs @@ -365,10 +365,15 @@ pub fn EmojiPicker( current.set(i); } }; - // A group not drawn yet is drawn now, with the rest, and gone to in - // the next frame. + // An already drawn group can still be at the temporary bottom, with + // too little trailing content to reach the top. Draw the rest before + // jumping when the heading is missing or would be clamped there. + let can_align = match (results.get_untracked(), headings().get(i)) { + (Some(results), Some(heading)) => heading.offset_top() <= results.scroll_height() - results.client_height(), + _ => false, + }; match drawing.get_value() { - Some(drawn) if drawn.try_get_untracked().is_some_and(|groups| groups <= i) => { + Some(drawn) if drawn.try_get_untracked().is_some_and(|groups| groups < Group::ALL.len()) && !can_align => { let _ = drawn.try_set(Group::ALL.len()); request_animation_frame(go); } diff --git a/e2e/emoji-picker.fixture.spec.ts b/e2e/emoji-picker.fixture.spec.ts index 7f5e206d..a6bc77ca 100644 --- a/e2e/emoji-picker.fixture.spec.ts +++ b/e2e/emoji-picker.fixture.spec.ts @@ -184,6 +184,24 @@ function headingTop(picker: Locator, name: string) { test("the groups' bar brings a group to the top, and marks the one in view as the grid scrolls", async ({ page }) => { await serve(page); const { dialog } = await compose(page); + // Keep Food as the last drawn group: its heading is already mounted, but + // later groups have not supplied the scroll room needed to put it at the top. + // This slow progressive-paint state must work without a second click. + await page.evaluate(() => { + const frame = window.requestAnimationFrame.bind(window); + const held: Array<() => void> = []; + window.requestAnimationFrame = (callback) => frame((time) => { + if (document.querySelectorAll(".emoji-group-heading").length === 8) { + held.push(() => callback(time)); + } else { + callback(time); + } + }); + (window as any).releaseEmojiFrames = () => { + window.requestAnimationFrame = frame; + held.splice(0).forEach((callback) => callback()); + }; + }); await dialog.getByRole("button", { name: "Add an emoji" }).click(); const picker = dialog.getByRole("region", { name: "Pepe emoji" }); const bar = picker.getByRole("group", { name: "Groups" }); @@ -191,8 +209,20 @@ test("the groups' bar brings a group to the top, and marks the one in view as th const marked = (name: string) => expect(bar.getByRole("button", { name, exact: true })).toHaveAttribute("aria-current", "true"); // Each button's face is its group's first emoji, still. await expect(bar.getByRole("button", { name: "Food and drink" }).locator("img")).toHaveAttribute("src", /pepe_tea\.still\.webp$/); + await expect(picker.locator(".emoji-group-heading")).toHaveCount(8); + const geometry = await grid.evaluate((grid) => { + const heading = [...grid.querySelectorAll("h4")].find((h) => h.textContent === "Food and drink")!; + return { + groups: grid.querySelectorAll("h4").length, offsetTop: heading.offsetTop, + scrollTop: grid.scrollTop, maxScrollTop: grid.scrollHeight - grid.clientHeight, + headingTop: heading.getBoundingClientRect().top - grid.getBoundingClientRect().top, + }; + }); + await test.info().attach("partial-group-geometry", { contentType: "application/json", body: JSON.stringify(geometry) }); + expect(geometry.offsetTop).toBeGreaterThan(geometry.maxScrollTop); await bar.getByRole("button", { name: "Food and drink" }).click(); await expect.poll(() => headingTop(picker, "Food and drink")).toBe(0); + await page.evaluate(() => (window as any).releaseEmojiFrames()); await marked("Food and drink"); await expect(bar.locator("[aria-current]")).toHaveCount(1); // Scrolled by hand, the mark follows the heading that has reached the top. From 3dce8d7a1be7fcfde424e79b7267f379e15fbc78 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 19:34:56 +0200 Subject: [PATCH 26/31] test(hosting): discover the deployed main module route --- e2e/allthing.spec.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/e2e/allthing.spec.ts b/e2e/allthing.spec.ts index 81227b3f..d01dc0e0 100644 --- a/e2e/allthing.spec.ts +++ b/e2e/allthing.spec.ts @@ -1164,9 +1164,14 @@ test.describe("hosting", () => { test("static assets are long-cached and the API is edge-cached", async ({ request }) => { const index = await request.get("/"); - const asset = /\/assets\/allthing-[0-9a-f]+\.wasm/.exec(await index.text())?.[0]; - expect(asset).toBeTruthy(); - const wasm = await request.get(asset!); + // The boot module comes from /wasm on Workers, or /assets on a static + // host. Discover its exact fingerprinted path, excluding idle splits; + // multiple main-module references must still fail this contract. + const modules = (await index.text()).match(/\/(?:assets|wasm)\/allthing-[0-9a-f]+\.wasm(?=["'\s<>])/g) ?? []; + expect(modules).toHaveLength(1); + const wasm = await request.get(modules[0]); + expect(wasm.status()).toBe(200); + expect(wasm.headers()["content-type"]).toBe("application/wasm"); expect(wasm.headers()["cache-control"]).toContain("immutable"); await request.get("/api/v1/home"); const second = await request.get("/api/v1/home"); From 291e194cd9e2d72bd11e231f2727b574a5761873 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 19:38:40 +0200 Subject: [PATCH 27/31] test(ci): reject recovered browser flakes --- CHANGELOG.md | 1 + playwright.config.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7486685f..1bfe2c17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch ### Fixed +- CI rejects browser tests that pass only on retry, so a flaky run cannot appear as a clean release check. - Choosing an emoji group while the picker is still drawing reaches its heading on the first click, including a group at the temporary bottom of the list. - Sort tabs show their selected state before the next feed hides read cards, keeping reading-history cleanup out of the tap handler. - Future-dated casts cannot outrank the present in For you or Following, including All time and early paint. Cached newest-cast payloads and index rankings exclude future timestamps before selecting their visible rows. Source reads use the clock when they finish, so casts posted while a response arrives are retained. Ingest retains up to five seconds of source clock skew in the existing buffer; implausible dates are discarded, and retained rows appear only when their timestamp is reached. diff --git a/playwright.config.ts b/playwright.config.ts index b40d048d..fa7fd1cf 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -28,6 +28,8 @@ export default defineConfig({ fullyParallel: false, workers: 1, retries: process.env.CI ? 1 : 0, + // A recovered retry is diagnostic evidence, not a clean release check. + failOnFlakyTests: Boolean(process.env.CI), reporter: process.env.CI ? [["list"], ["html", { open: "never" }]] : "list", use: { baseURL, From 99674b6687d4175fbca466fdf423f599e51a9460 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 19:42:42 +0200 Subject: [PATCH 28/31] test(feed): await live sorts and retain loaded images --- e2e/allthing.spec.ts | 57 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/e2e/allthing.spec.ts b/e2e/allthing.spec.ts index d01dc0e0..3bdbf510 100644 --- a/e2e/allthing.spec.ts +++ b/e2e/allthing.spec.ts @@ -162,23 +162,50 @@ test.describe("front page", () => { await shoot(page, "home"); }); - test("new and top re-rank the same pool without another API call", async ({ page }) => { + test("New reads latest casts and Top reuses trending without refetching Home", async ({ page }) => { + // This live read checks feed navigation without recording a presence beat. + await page.route("**/api/v1/presence", (route) => route.fulfill({ status: 404, json: { error: "Read-only test" } })); await page.goto(at("/")); await expect(firstCard(page)).toBeVisible(); + const latestRead = PAGES ? null : page.waitForResponse((response) => + new URL(response.url()).pathname === "/api/v1/latest" && response.request().method() === "GET", + ); const calls = await apiRequests(page, async () => { await page.locator(".sort-tabs a", { hasText: "new" }).click(); await expect(page).toHaveURL(/sort=new/); + if (latestRead) { + const response = await latestRead; + expect(response.status()).toBe(200); + const hashes = (await response.json()).pool.map((cast: { hash: string }) => cast.hash); + // URL changes and carried cards can precede the new resource. Check + // the actual Latest payload before judging the visible chronology. + await expect.poll(() => page.locator(".cast-card").evaluateAll( + (cards, allowed) => cards.length > 0 && cards.every((card) => allowed.includes(card.getAttribute("data-hash")!)), + hashes, + )).toBe(true); + } await expect(firstCard(page)).toBeVisible(); }); - // Prefetches of posts may run meanwhile; the feed itself is not refetched. + // New uses its own source; the previous trending payload is reused. expect(calls.filter((c) => /\/api\/v1\/home|feed\/trending/.test(c)), "sorting is local").toHaveLength(0); - const times = await page.locator(".cast-card").evaluateAll((c) => c.map((e) => Number(e.getAttribute("data-ts")))); - expect(times).toEqual([...times].sort((a, b) => b - a)); - - await page.locator(".sort-tabs a", { hasText: "top" }).click(); - await expect(page).toHaveURL(/sort=top/); - const points = await page.locator(".cast-card").evaluateAll((c) => c.map((e) => Number(e.getAttribute("data-points")))); - expect(points).toEqual([...points].sort((a, b) => b - a)); + if (!PAGES) expect(calls.filter((call) => /\/api\/v1\/latest/.test(call))).toHaveLength(1); + await expect(async () => { + const times = await page.locator(".cast-card").evaluateAll((c) => c.map((e) => Number(e.getAttribute("data-ts")))); + expect(times.length).toBeGreaterThan(0); + expect(times).toEqual([...times].sort((a, b) => b - a)); + }).toPass({ timeout: 5000 }); + + const topCalls = await apiRequests(page, async () => { + await page.locator(".sort-tabs a", { hasText: "top" }).click(); + await expect(page).toHaveURL(/sort=top/); + // The selected sort paints before its rows are reordered. + await expect(async () => { + const points = await page.locator(".cast-card").evaluateAll((c) => c.map((e) => Number(e.getAttribute("data-points")))); + expect(points.length).toBeGreaterThan(0); + expect(points).toEqual([...points].sort((a, b) => b - a)); + }).toPass({ timeout: 5000 }); + }); + expect(topCalls.filter((call) => /\/api\/v1\/home|feed\/trending/.test(call)), "Top reuses trending").toHaveLength(0); }); test("a feed page that fails to load is tried again", async ({ page }) => { @@ -675,13 +702,16 @@ test.describe("threads and navigation", () => { await expect(page).toHaveURL(new RegExp(`/p/${hash}$`)); }); - test("back lays out the feed's images at their size before they load", async ({ page }) => { + test("Back preserves loaded feed images and their exact size", async ({ page }) => { + // Keep this image/navigation check read-only on the live deployment. + await page.route("**/api/v1/presence", (route) => route.fulfill({ status: 404, json: { error: "Read-only test" } })); await page.goto(at("/")); await expect(firstCard(page)).toBeVisible(); // A card with a single image, scrolled past so its image has loaded. const image = page.locator(".cast-card > .media-grid.n1 .tile-image img").first(); await image.scrollIntoViewIfNeeded(); await expect.poll(() => image.evaluate((img: HTMLImageElement) => img.complete && img.naturalHeight > 0)).toBe(true); + const original = await image.elementHandle(); const hash = await image.evaluate((img) => img.closest(".cast-card")!.getAttribute("data-hash")!); const height = await image.evaluate((img) => Math.round(img.getBoundingClientRect().height)); expect(height).toBeGreaterThan(50); @@ -698,10 +728,13 @@ test.describe("threads and navigation", () => { }, ); await page.goBack(); + await expect(page).toHaveURL(new RegExp(`${at("/")}$`)); const again = page.locator(`.cast-card[data-hash="${hash}"] > .media-grid.n1 .tile-image img`); await expect(again).toBeAttached(); - // Its box is already the loaded image's size: nothing below it will move. - expect(await again.evaluate((img: HTMLImageElement) => img.complete)).toBe(false); + // Back remounts the retained feed: its loaded image and exact box stay + // intact even while newly requested images would still be delayed. + expect(await again.evaluate((img, kept) => img === kept, original)).toBe(true); + expect(await again.evaluate((img: HTMLImageElement) => img.complete && img.naturalHeight > 0)).toBe(true); expect(Math.abs((await again.evaluate((img) => img.getBoundingClientRect().height)) - height)).toBeLessThanOrEqual(2); }); From 710e05dd294e076d416fc8aed1f6e441a47d1d0a Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 20:42:50 +0200 Subject: [PATCH 29/31] ci: isolate smoothness from parallel functional fixtures --- .github/workflows/ci.yml | 8 +-- CHANGELOG.md | 1 + docs/PERFORMANCE.md | 2 + scripts/test-browser-fixtures.sh | 28 ++++++++++ tests/browser-fixture-phases.test.mjs | 76 +++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 scripts/test-browser-fixtures.sh create mode 100644 tests/browser-fixture-phases.test.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c550e988..9a7c765c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -126,7 +126,7 @@ jobs: browser: name: browser regressions (fixtures) runs-on: ubuntu-24.04 - # The suite takes 26 to 29 minutes; 30 cut runs off at their last specs. + # Build, functional fixtures, quiet smoothness and static checks share this cap. timeout-minutes: 45 env: WRANGLER_SEND_METRICS: "false" @@ -152,11 +152,13 @@ jobs: - run: npx playwright install --with-deps chromium - run: bash scripts/build.sh - name: Test the local build without live data - run: npx playwright test '\.fixture\.spec\.ts$' + run: sh scripts/test-browser-fixtures.sh - name: Test the static copy run: | bash scripts/build-pages.sh - E2E_PAGES=1 npx playwright test e2e/static-body-limit.fixture.spec.ts e2e/static-metadata.fixture.spec.ts e2e/static-navigation.fixture.spec.ts e2e/static-follows.fixture.spec.ts e2e/preloaded-replies.fixture.spec.ts e2e/poll.fixture.spec.ts + E2E_PAGES=1 npx playwright test e2e/static-body-limit.fixture.spec.ts e2e/static-metadata.fixture.spec.ts e2e/static-navigation.fixture.spec.ts e2e/static-follows.fixture.spec.ts e2e/preloaded-replies.fixture.spec.ts e2e/poll.fixture.spec.ts --output=test-results/static + env: + PLAYWRIGHT_HTML_OUTPUT_DIR: playwright-report/static - name: Upload browser failure reports if: failure() uses: actions/upload-artifact@v6 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bfe2c17..57e0f24f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch ### Development +- CI runs functional browser fixtures with two workers, followed by smoothness measurements alone with one. Both phases run and keep separate reports even after a failure, under the same checks and timing limits. - Cold-load performance checks retain sanitized per-sample LCP, network, cache and long-task diagnostics, including on failure, in a seven-day Actions artifact. Their timing limits, cold contexts and sample count are unchanged. - Browser regressions use past timestamps relative to the page’s own clock, wait for restored seen rows and the latest presence-cache expiry, and preserve their ordering, privacy, navigation and timing checks, including a deliberately delayed count refresh. - Startup checks distinguish the main WebAssembly module from idle-loaded parts, and range navigation waits for the actual New feed response. diff --git a/docs/PERFORMANCE.md b/docs/PERFORMANCE.md index 29e9f0a1..cc732d30 100644 --- a/docs/PERFORMANCE.md +++ b/docs/PERFORMANCE.md @@ -19,6 +19,8 @@ Each cold-home sample logs its first-card and LCP times, the LCP element and ima ## Smoothness +CI runs functional fixture files with two workers, then runs `smoothness.fixture.spec.ts` alone with one worker (`scripts/test-browser-fixtures.sh`). Both phases run even if the first fails, and either failure fails the existing browser job. Their HTML reports and test results are kept separately, including from the later static checks; the production performance job, test retries, timing assertions and 45-minute job cap are unchanged. + How the app answers a reader's taps, clicks and scrolls: `e2e/smoothness.fixture.spec.ts`, which CI's browser job runs on every pull request and push to `main`, on the local build with the Worker's API, the node and the images as stand-ins (the API answers after 60 to 180 ms). A signed-in reader with an approved key, on a phone (390 × 844, touch, the CPU slowed 2×) and on a computer (1280 × 900, a mouse): - taps the sort tabs: new, top, hot; diff --git a/scripts/test-browser-fixtures.sh b/scripts/test-browser-fixtures.sh new file mode 100644 index 00000000..5d1adce8 --- /dev/null +++ b/scripts/test-browser-fixtures.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# SPDX-License-Identifier: AGPL-3.0-or-later +# Keep calibrated smoothness measurements alone on the runner. The other +# fixtures run first with two workers, under their existing assertions. +set -u +cd "$(dirname "$0")/.." || exit 1 + +if [ "$#" -ne 0 ]; then + echo "Usage: sh scripts/test-browser-fixtures.sh" >&2 + exit 2 +fi + +functional=0 +echo "Functional fixtures (2 workers)" +PLAYWRIGHT_HTML_OUTPUT_DIR=playwright-report/functional \ + npx playwright test '^(?!.*[/\\]smoothness\.fixture\.spec\.ts$).*\.fixture\.spec\.ts$' \ + --workers=2 --output=test-results/functional || functional=$? + +smoothness=0 +echo "Smoothness fixtures (1 worker, after functional fixtures finish)" +PLAYWRIGHT_HTML_OUTPUT_DIR=playwright-report/smoothness \ + npx playwright test '[/\\]smoothness\.fixture\.spec\.ts$' \ + --workers=1 --output=test-results/smoothness || smoothness=$? + +# Run both phases, including after an assertion failure or runner error. +if [ "$functional" -ne 0 ] || [ "$smoothness" -ne 0 ]; then + exit 1 +fi diff --git a/tests/browser-fixture-phases.test.mjs b/tests/browser-fixture-phases.test.mjs new file mode 100644 index 00000000..37b1d19e --- /dev/null +++ b/tests/browser-fixture-phases.test.mjs @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +import assert from "node:assert/strict"; +import { spawnSync } from "node:child_process"; +import { chmod, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import path from "node:path"; +import { test } from "node:test"; +import { fileURLToPath } from "node:url"; + +const script = fileURLToPath(new URL("../scripts/test-browser-fixtures.sh", import.meta.url)); + +async function run(functional, smoothness, args = []) { + const scratch = await mkdtemp(path.join(tmpdir(), "allthing-browser-phases-")); + try { + const log = path.join(scratch, "calls"); + const npx = path.join(scratch, "npx"); + await writeFile(npx, `#!/bin/sh +printf 'phase\nhtml=%s\nci=%s\n' "$PLAYWRIGHT_HTML_OUTPUT_DIR" "$CI" >> "$PHASE_LOG" +printf 'arg=%s\n' "$@" >> "$PHASE_LOG" +case "$*" in + *--workers=2*) exit "$FUNCTIONAL_EXIT" ;; + *--workers=1*) exit "$SMOOTHNESS_EXIT" ;; + *) exit 90 ;; +esac +`); + await chmod(npx, 0o755); + const result = spawnSync("sh", [script, ...args], { + encoding: "utf8", + env: { ...process.env, PATH: `${scratch}:${process.env.PATH}`, CI: "1", PHASE_LOG: log, FUNCTIONAL_EXIT: String(functional), SMOOTHNESS_EXIT: String(smoothness) }, + }); + const calls = await readFile(log, "utf8").catch((error) => { + if (error.code === "ENOENT") return ""; + throw error; + }); + return { ...result, calls: calls.split("phase\n").filter(Boolean).map((call) => call.trim().split("\n")) }; + } finally { + await rm(scratch, { recursive: true, force: true }); + } +} + +test("runs functional then quiet smoothness with separate reports and unchanged CI policy", async () => { + const result = await run(0, 0); + assert.equal(result.status, 0, result.stderr); + assert.equal(result.calls.length, 2); + assert.deepEqual(result.calls.map((call) => call.slice(0, 2)), [ + ["html=playwright-report/functional", "ci=1"], + ["html=playwright-report/smoothness", "ci=1"], + ]); + assert.deepEqual(result.calls.map((call) => call.filter((arg) => arg.startsWith("arg=--"))), [ + ["arg=--workers=2", "arg=--output=test-results/functional"], + ["arg=--workers=1", "arg=--output=test-results/smoothness"], + ]); +}); + +test("still measures smoothness when functional assertions or the runner fail", async () => { + for (const status of [1, 127]) { + const result = await run(status, 0); + assert.equal(result.status, 1); + assert.equal(result.calls.length, 2); + assert.ok(result.calls[1].includes("arg=--workers=1")); + } +}); + +test("either phase failing makes the aggregate fail", async () => { + for (const statuses of [[0, 1], [1, 1]]) { + const result = await run(...statuses); + assert.equal(result.status, 1); + assert.equal(result.calls.length, 2); + } +}); + +test("rejects extra CLI arguments instead of overriding the phase worker counts", async () => { + const result = await run(0, 0, ["--workers=8"]); + assert.equal(result.status, 2); + assert.equal(result.calls.length, 0); +}); From 938732d31f22513fec3d9918043bfb5d03f972d4 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 20:49:58 +0200 Subject: [PATCH 30/31] test(video): verify held keyboard focus before sound activation --- CHANGELOG.md | 1 + e2e/video-sound-focus.fixture.spec.ts | 45 +++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57e0f24f..de62bf5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch ### Development - CI runs functional browser fixtures with two workers, followed by smoothness measurements alone with one. Both phases run and keep separate reports even after a failure, under the same checks and timing limits. +- Video keyboard checks verify a held Space press on the original pointer-focused control before release, retaining bounded input and media diagnostics on failure. - Cold-load performance checks retain sanitized per-sample LCP, network, cache and long-task diagnostics, including on failure, in a seven-day Actions artifact. Their timing limits, cold contexts and sample count are unchanged. - Browser regressions use past timestamps relative to the page’s own clock, wait for restored seen rows and the latest presence-cache expiry, and preserve their ordering, privacy, navigation and timing checks, including a deliberately delayed count refresh. - Startup checks distinguish the main WebAssembly module from idle-loaded parts, and range navigation waits for the actual New feed response. diff --git a/e2e/video-sound-focus.fixture.spec.ts b/e2e/video-sound-focus.fixture.spec.ts index 32618e41..c9b7faa1 100644 --- a/e2e/video-sound-focus.fixture.spec.ts +++ b/e2e/video-sound-focus.fixture.spec.ts @@ -33,6 +33,31 @@ test.beforeEach(async ({ page }) => { body: readFileSync(path.join(fixtures, file)), contentType: type, headers: { "access-control-allow-origin": "*" }, }); }); + // Retain a short trusted-input/media timeline if the keyboard transition + // fails, so native activation can be distinguished from a focus/state change. + await page.addInitScript(() => { + const events: Array> = []; + (window as any).soundInput = events; + const record = (event: Event) => { + const target = event.target instanceof Element ? event.target : null; + if (target && !target.closest(".post .video")) return; + queueMicrotask(() => { + const player = document.querySelector(".post .video"); + const video = player?.querySelector("video"); + events.push({ + at: performance.now(), type: event.type, trusted: event.isTrusted, prevented: event.defaultPrevented, + key: (event as KeyboardEvent).key, detail: (event as MouseEvent).detail, + target: target?.className, active: document.activeElement?.className, focused: document.hasFocus(), + label: player?.querySelector(".video-sound")?.textContent, + muted: video?.muted, paused: video?.paused, sound: localStorage.getItem("allthing.sound"), + }); + if (events.length > 64) events.shift(); + }); + }; + for (const kind of ["pointerdown", "pointerup", "touchend", "keydown", "keypress", "keyup", "click", "focus", "blur", "volumechange", "playing", "pause"]) { + window.addEventListener(kind, record, true); + } + }); // The reply's video sits far below, so only one is in view at a time. await page.addInitScript(() => { document.addEventListener("DOMContentLoaded", () => { @@ -61,20 +86,36 @@ for (const width of [1280, 390]) { const before = await page.evaluate(() => window.scrollY); const source = await video.getAttribute("src"); await activateVisible(sound, hasTouch); + let failed = true; try { await expect.poll(() => page.evaluate(() => window.scrollY), { timeout: 2000 }).toBe(before); const enabled = player.getByRole("button", { name: "Sound on · tap to mute", exact: true }); await expect(enabled).toBeFocused(); await expect.poll(() => video.evaluate((v) => !v.muted && !v.paused)).toBe(true); expect(await page.evaluate(() => localStorage.getItem("allthing.sound"))).toBe("on"); - // Keyboard activation still works after pointer focus. - await page.keyboard.press("Space"); + // Hold Space on the pointer-focused control until its keydown has + // been processed, then release it for the native button activation. + // Do not refocus: the same node must keep focus throughout. + const pointerFocused = await enabled.elementHandle(); + await page.keyboard.down("Space"); + try { + await expect(enabled).toBeFocused(); + expect(await enabled.evaluate((button, original) => button === original, pointerFocused)).toBe(true); + await expect(enabled).toHaveAttribute("data-press", "down"); + await expect.poll(() => video.evaluate((v) => !v.muted && !v.paused)).toBe(true); + } finally { + await page.keyboard.up("Space"); + } await expect(sound).toBeFocused(); await expect.poll(() => video.evaluate((v) => v.muted && !v.paused)).toBe(true); expect(await page.evaluate(() => localStorage.getItem("allthing.sound"))).toBeNull(); expect(await page.evaluate(() => window.scrollY)).toBe(before); expect(await video.getAttribute("src")).toBe(source); + failed = false; } finally { + if (failed) { + await info.attach("sound-input", { contentType: "application/json", body: JSON.stringify(await page.evaluate(() => (window as any).soundInput), null, 2) }); + } await page.screenshot({ path: info.outputPath(`video-sound-focus-${width}.png`) }); } }); From c91f38eb82bd029e67b41b1eb555a8cf9cabf612 Mon Sep 17 00:00:00 2001 From: ael-dev3 <183124839+ael-dev3@users.noreply.github.com> Date: Fri, 23 Oct 2026 21:15:25 +0200 Subject: [PATCH 31/31] test: wait for sampled routes before checking Back --- CHANGELOG.md | 2 ++ e2e/kept-front.fixture.spec.ts | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de62bf5f..33e14a09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ All notable changes to Allthing are recorded here. The format follows [Keep a Ch ### Development +- Back-navigation checks wait for sampled Home and post frames before returning, preserving their exact retained-card, restored-height, position and request assertions. + - CI runs functional browser fixtures with two workers, followed by smoothness measurements alone with one. Both phases run and keep separate reports even after a failure, under the same checks and timing limits. - Video keyboard checks verify a held Space press on the original pointer-focused control before release, retaining bounded input and media diagnostics on failure. - Cold-load performance checks retain sanitized per-sample LCP, network, cache and long-task diagnostics, including on failure, in a seven-day Actions artifact. Their timing limits, cold contexts and sample count are unchanged. diff --git a/e2e/kept-front.fixture.spec.ts b/e2e/kept-front.fixture.spec.ts index d3154972..e7163ffb 100644 --- a/e2e/kept-front.fixture.spec.ts +++ b/e2e/kept-front.fixture.spec.ts @@ -83,17 +83,25 @@ for (const size of [ }; requestAnimationFrame(frame); }, before.hash); + const frames = () => page.evaluate(() => (window as Window & { __frames?: Frame[] }).__frames!); + // The sampler must have the page being left, even when navigation + // can complete before its next frame on a fast retained route. + await expect.poll(async () => (await frames()).some((f) => f.path === "/" && f.top !== null), + { timeout: 3000, message: "a frame of the front page before leaving" }).toBe(true); await page.locator(`#app .cast-card[data-hash="${before.hash}"] .cast-text`).click(); await expect(page.locator("#app .post")).toBeVisible(); // None of the front page is in the post's page. await expect(page.locator("#app .cast-list .cast-card")).toHaveCount(0); + // DOM visibility can precede a paint. Record the post before Back, + // rather than letting both route changes fit between sampled frames. + await expect.poll(async () => (await frames()).findIndex((f) => f.path === `/p/${before.hash}` && f.top === null), + { timeout: 3000, message: "a frame of the post before Back" }).toBeGreaterThan(0); await page.goBack(); await expect(page).toHaveURL(/\/$/); const after = () => page.evaluate((hash) => { const card = document.querySelector(`#app .cast-card[data-hash="${hash}"]`) as HTMLElement & { kept?: boolean }; return { same: card.kept === true, top: card.getBoundingClientRect().top, count: document.querySelectorAll("#app .cast-card").length }; }, before.hash); - const frames = () => page.evaluate(() => (window as Window & { __frames?: Frame[] }).__frames!); // Where the reader left the card: its last frame before the post. Not // where it was before the click, which can scroll the page first: a // card not yet still as Playwright checks it is scrolled into view