Skip to content

test(e2e) + feature(social): the social-e2e feed surface spec (3.26.0) - #702

Merged
jacoby149 merged 7 commits into
devfrom
test/social-e2e-feed
Aug 28, 2026
Merged

test(e2e) + feature(social): the social-e2e feed surface spec (3.26.0)#702
jacoby149 merged 7 commits into
devfrom
test/social-e2e-feed

Conversation

@jacoby149

Copy link
Copy Markdown
Owner

What

The feed surface spec for the social-e2e lane (lane 223) — e2e/tests/social-feed.spec.ts.

API floor (no browser) pins what src/data/feed.ts readFeed actually queries: getMyGroups → drop the node-default discover group → ONE /v3/read over the rest (limit 50, NO server-side sort) → client-side sort by created_at. Asserts: one read over two followed followers groups returns both creators' posts (contains, each once), newest-first (and oldest reverses), the read is scoped to exactly the followed groups (discover dropped — a discover-only post is absent), and a fresh user's read short-circuits to an empty feed. The I3 anti-test proves a non-follower's group post is absent from the app's feed read.

Browser gauntlet (pre-authed via the token cookie — the D42 login flow belongs to the auth specs, the capstone drives it cold): /feed renders a followed creator's post → post via the composer → reload → the feed still renders and the post persists.

Logging (house style, kept in): readFeed + createPost log the [social-feed] flow; the gauntlet asserts the log sequence (read → create → read) with no failures.

The own-followers finding (handed to the groups lane, 224)

A user's OWN public post does not surface in their OWN /feed: followersGroupId addresses the well-known web10.app/groups/{u}/followers, which the node's groups/create can't mint (it mints {provider}/groups/users/{u}/{slug}), and ensureFollowers is never called at runtime. The gauntlet verifies the posted content persists by reading it back from the discover board (a public post is attached there). The own-followers provisioning / ID-scheme alignment is the groups surface's concern — documented in .context/lane-social-e2e-feed-own-followers.md (gitignored).

Verification

  • scripts/run-e2e.sh tests/social-feed.spec.ts green (4/4, stable across repeated runs — the discover-board persistence check polls for ClickHouse eventual consistency).
  • tsc clean on the new spec (the 11 pre-existing e2e type errors in other specs are untouched; CI runs no tsc step).
  • bun run build clean in web10-social.
  • No user-visible change (logging only) — the e2e gauntlet is the render verification.

Notes

…pp's exact /feed read pinned + I3 + render→post→reload gauntlet (3.26.0)

The API floor pins what readFeed actually queries (getMyGroups → drop
discover → one /v3/read over the rest, limit 50, client-side sort) and the
I3 anti-test (a non-follower's group post is absent). The browser gauntlet
drives the real app (pre-authed via token cookie): /feed renders a followed
creator's post → post via the composer → reload → the feed still renders and
the post persists. readFeed + createPost gain [social-feed] flow logging,
asserted as a log sequence. The own-followers-group finding (a user's own
post doesn't surface in their own feed — well-known ID shape the API can't
mint + ensureFollowers never called) is handed to the groups lane via a
.context/ note; the gauntlet verifies persistence via the discover board.
…the own-followers-group provisioning

Operator: 'users own DEFINITELY belongs in their own feed'. Four bugs in
src/data/groups.ts + posts.ts: (1) followersGroupId used the well-known
web10.app/groups/{u}/followers shape the node's groups/create can't mint (it
mints {provider}/groups/users/{u}/{slug}); (2) ensureFollowers created with
name {u}/followers (double-username mismatch); (3) ensureFollowers used
member_key web10.app/users/{u} but the API compares member_key to the bare
JWT username, so the user was never a member; (4) ensureFollowers was never
called. Fixed: followersGroupId returns the node-minted shape (provider from
the token); ensureFollowers creates with name 'followers' + the owner's bare
username; createPost (public/friends) calls ensureFollowers before attaching.
The e2e gauntlet now asserts the user's OWN post appears in their OWN feed and
persists across reload. follows.test.ts updated to the minted shape. Same
pattern still affects close-friends + DMs (settings/private + messages lanes).
# Conflicts:
#	knowledge/strategy/parallel-execution.md
#	marketing/web10-social/src/__tests__/data/follows.test.ts
#	marketing/web10-social/src/data/groups.ts
@jacoby149
jacoby149 merged commit 260cf3f into dev Aug 28, 2026
7 checks passed
jacoby149 added a commit that referenced this pull request Aug 28, 2026
jacoby149 added a commit that referenced this pull request Aug 28, 2026
…ation lives (3.25.1) (#706)

* docs(kb): ad dissemination — design-under-discussion on where the curation lives (3.25.1)

Operator reframe: the ad should be a property of the post read (opted-in
posts come back with their curated ad, curated from the author's catalog per
the author's preference), not a client-side computation — 'more clickhousey',
a platform capability any app gets for free.

The doc (ads-dissemination.md) lays out the reframe, the strong argument for
it (the read already does read-time projections — media URLs, HLS manifest
minting, power-mean ranking), the stateful-curation wall (a stateless query
can't hold per-viewer/per-session state), the three options (client-side /
data-layer / hybrid), and the open questions. Not a decision — the KB-side
starting point for the discussion. ads.md Dissemination section points to it.

* docs(kb): ad dissemination — converged design: per-doc ad_preference + catalogs + love-based curation (3.25.1)

The design converged: every document has an ad_preference (which catalog to
curate from + a mode + a target for pinned); a user has multiple ad catalogs
(the Spotify-playlist model — an ad in several); on read, ClickHouse curates
the ad from the chosen catalog per the mode and serves doc + ad together.

The 'love' idea dissolves the statefulness wall: least-loved (round_robin) /
most-loved (greedy) is a property of the data, not the viewer — a
deterministic function of current engagement, the same ref-count machinery
power-mean ranking already reads in SQL. No per-viewer state, no
write-on-read.

Added the mermaid diagram, the ClickHouse feasibility read (window-function +
join, the house pattern), the value prop, and 11 serious open questions.
curateAds (3.26.0) is largely superseded.

* chore(changelog): renumber ad-dissemination entry to 3.25.2 (3.25.1 taken by merged social-e2e follows fix)

* docs(kb): ad dissemination — signal×strategy enums, node-level ad density, authenticator Ads tab, greedy reframed (3.25.2)

Converged further:
- The mode is a signal × strategy pair (expandable: reaction round robin,
  comment round robin, you name it) + a scope enum (global / per_viewer).
- A node-level ad density setting — the % of posts that get an ad at all, the
  operator's fatigue throttle (deterministic pseudo-random roll in the query).
- The authenticator gets a new Ads tab (ads upload + catalog making), which
  makes catalogs first-class (leaning a catalog doc).
- Greedy reframed as 'show my proven best' (complementary to round_robin's
  'give everything a fair shot'); the cold-start is the distinction, not a bug.

* chore(changelog): renumber ad-dissemination entry to 3.25.3 (3.25.2 taken by merged Messages e2e #707)

* chore(changelog): renumber ad-dissemination entry to 3.26.1 (above merged feed spec 3.26.0 #702)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant