Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions apps/web/src/app/waves/_components/waves-list-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
import { useWavesTagFilter } from "@/app/waves/_context";
import { useBottomPagination } from "@/core/hooks";
import { Button } from "@ui/button";
import { DEFAULT_OBSERVER } from "@/consts/observer";
import i18next from "i18next";
import { sentry } from "@/core/sentry/lazy-sentry";

Expand All @@ -40,11 +39,15 @@ export function WavesListView({ feedType, username }: Props) {
// server-side and each page still arrives full (client-side filtering would
// shrink pages). Note esync actually drops muted authors here, unlike the
// Hive bridge, which only flags them `stats.gray`.
// Ecency's own moderation mutes are not this parameter's job: esync applies
// that list to every waves request on top of the observer's, so it holds for
// signed-in viewers too. The fallback below only keeps anonymous requests
// shaped like the rest.
const observer = username || DEFAULT_OBSERVER;
//
// Logged out this stays undefined rather than falling back to Ecency's
// moderation account. That fallback used to be what filtered the anonymous
// feed; esync now applies the moderation mute list to every waves request on
// its own, so sending it changed nothing except the cache tier: any observer
// marks a request personalised, and personalised requests skip the 60s shared
// response cache. Every anonymous visitor was paying for a per-viewer cache
// entry that no other viewer could ever reuse.
const observer = username;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. Missing observer regression coverage 📘 Rule violation ▣ Testability

The changed waves and shorts request behavior is functional code, but this PR adds or updates no
automated test that verifies anonymous requests omit observer while authenticated requests still
pass username. This leaves the cache-tier change and logged-in behavior unprotected against
regression.
Agent Prompt
## Issue description
The waves views now pass `undefined` for anonymous observers, but no test in this change exercises the new request behavior or verifies that authenticated usernames remain observers.

## Issue Context
Add tests for both `WavesListView` and `WavesReelsView` (or their query option integration) that assert anonymous requests omit `observer` and authenticated requests include the username. Cover the relevant feed and shorts paths.

## Fix Focus Areas
- apps/web/src/app/waves/_components/waves-list-view.tsx[50-53]
- apps/web/src/app/waves/_components/waves-reels-view.tsx[22-26]
- packages/sdk/src/modules/posts/queries/get-waves-feed-query-options.ts[120-128]
- packages/sdk/src/modules/posts/queries/get-shorts-feed-query-options.ts[131-139]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

const queryOptions = useMemo(() => {
if (selectedSource) {
return getWavesFeedQueryOptions({ containers: [selectedSource], observer });
Expand Down
6 changes: 4 additions & 2 deletions apps/web/src/app/waves/_components/waves-reels-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { Button } from "@ui/button";
import { useInfiniteDataFlow } from "@/utils";
import { WavesReelItem } from "@/app/waves/_components/waves-reel-item";
import { WavesFastReplyDialog } from "@/app/waves/_components/waves-fast-reply-dialog";
import { DEFAULT_OBSERVER } from "@/consts/observer";

interface Props {
username?: string;
Expand All @@ -20,7 +19,10 @@ interface Props {
* Selected via the "Shorts" source tab; renders in place of the wave card list.
*/
export function WavesReelsView({ username }: Props) {
const observer = username || DEFAULT_OBSERVER;
// Undefined when logged out, like the waves list: esync applies the
// moderation mute list to the shorts feed itself, and an observer would only
// push the request off the shared 60s response cache (see waves-list-view).
const observer = username;
const queryOptions = useMemo(() => getShortsFeedQueryOptions({ observer }), [observer]);

const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading, isError, refetch } =
Expand Down
16 changes: 9 additions & 7 deletions apps/web/src/consts/observer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
* swapping to the logged-in user client-side would filter every page except
* the one people actually look at. Feeds personalise instead at the server,
* where cache-policy already marks those tiers user-specific.
* 3. This is NOT how Ecency's moderation mutes reach the waves feed. An
* observer only ever carries the mute list of whoever is viewing, so before
* esync applied the moderation list itself, signed-in users (who send their
* own name) got none of it. esync now ANDs `@ecency`'s on-chain mutes into
* every waves query on top of the observer's, so muting an account there is
* what takes it out of the feed for everyone. Bridge reads still behave as
* described above.
* 3. This is NOT how Ecency's moderation mutes reach the waves feed, and the
* waves feed no longer sends this default at all. An observer only ever
* carries the mute list of whoever is viewing, so before esync applied the
* moderation list itself, signed-in users (who send their own name) got none
* of it. esync now ANDs `@ecency`'s on-chain mutes into every waves query on
* top of the observer's, so muting an account there is what takes it out of
* the feed for everyone, and the waves views pass `undefined` when logged
* out so the request stays on the shared response cache. Bridge reads still
* behave as described above.
* 4. Kept as a plain literal on purpose. This mirrors `CONFIG.defaultObserver`
* in @ecency/sdk, but reading it from the SDK would make every module that
* touches an observer depend on the SDK being mocked in specs, and several
Expand Down
Loading