feat: v4 client migration — indexOnly likes, single hashtag, ranked Top tab; devnet cutover - #324
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…shtag, author fields)
NEXT_PUBLIC_CONTRACT_TOPOLOGY=v4 selects a descriptor carrying v3's document graph plus the like-overhaul deltas: indexOnly like/likeReply shapes (agreement-bound postAuthor/replyAuthor + like.hashtag, owner-first reads lowering onto byLiker, byAuthorTimePost/byAuthorTimeReply notification indexes), the inline single post.hashtag ('' = untagged, postHashtag doctype absent), and required poster-attested author fields. v2/v3 descriptors are byte-identical to before.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… the v4 arm
Creates carry the agreement-bound {postId, hashtag, postAuthor} (likeReply: {replyId, replyAuthor}) sourced from the target the UI holds, confirm via waitForAffectedState (indexOnly never resolves ExecutionProved), and never trust the returned document or its id — a reported failure is re-checked against the byLiker readback before being believed. Unlike recovers the full delete tuple (consensus createdAt + synthesized id) from byAuthorTimePost/byAuthorTimeReply, with a session cache keyed (kind, owner, target), and hands a fully-populated Document to the SDK delete. Like notification read-state re-keys to (owner, target) on v4; the likes modal tolerates the byPost projection's missing createdAt. The SDK init path issues a proved non-v4 warm-up query so the first v4 contract read never races the PV12-start protocol ratchet, and stale-quorum errors now trigger the reconnect path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…st.tagAndTime
Post/reply creates set the poster-attested author (== signer) and posts the first hashtag of their PUBLIC content ('' untagged) — teasers only for private posts, so encrypted text never leaks into the index. Tombstones carry author and hashtag over verbatim: author must keep equalling ownerId, and hashtag is client-immutable because existing likes repeated it under the consensus agreement. The postHashtag fire-and-forget writes are skipped entirely on v4; tag pages list post.tagAndTime directly, hashtag search counts ride the same index, trending renders its existing empty state (a ranked trending surface is deliberately out of scope), and hashtag validation short-circuits to valid (no secondary write exists to have failed).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A thin wrapper over documents.ranked() covering the three purchased axes (global byPost, hashtag-pinned byHashtagPost, author-pinned byAuthorPost), filtering the zero-count groups preallocation leaves in every page. Surfaced in one place as proof: the profile Top filter (v4 only) renders the author's top posts in proved ranking order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The v3 describe now runs on both v3 and v4 (same document graph; the reply-like case doubles as live likeReply indexOnly coverage) and asserts /about prints whatever topology the env file declares. A new v4-gated describe drives the full like lifecycle through the real UI on moutai: tagged post -> tag page listing (tagAndTime), like -> reload persistence (byLiker) + count (countable byPost), batched feed membership, unlike (tuple recovery + delete-by-values) -> re-like, and the ranked profile Top tab. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The reveal assertion resolved the card through a locator filtered on HAVING a sensitive-gate — but clicking Show unmounts the gate, so the locator could no longer match the very card it revealed and the assertion timed out on every environment (reproduced on the pristine base commit against testnet, so pre-existing, not a topology regression). Address the card by its captured post id instead, which also lets the three mode tests behind it in the serial group run. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Points the devnet deployment at the v4 draft Aux325ifCRkYUteevirCv7ptHm3YB2g7PbMo8UjQwoz with NEXT_PUBLIC_CONTRACT_TOPOLOGY=v4. The v3 contract 4UW9im1y... stays on chain unused. The final v4 re-registration (hashtag optional under upstream null-skip) comes later; this draft is the full QA target until then. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
🕓 Ready for review — 4 ahead in queue (commit ce04f62) |
Deploying yappr with
|
| Latest commit: |
ce04f62
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://836a4098.yappr.pages.dev |
| Branch Preview URL: | https://feat-v4-client.yappr.pages.dev |
Deploying yappr-v2 with
|
| Latest commit: |
ce04f62
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://c1d1ac40.yappr-v2.pages.dev |
| Branch Preview URL: | https://feat-v4-client.yappr-v2.pages.dev |
…indexOnly likers pagination Three fixes from the migration review: (1) the v4 like-notification id now includes the like's consensus createdAt (carried by the byAuthorTimePost projection the notification query already reads), so an unlike-then-re-like surfaces as a new unread instead of arriving permanently read against the persisted readIds set; (2) background tuple-cache warm-ups are guarded by a per-key monotonic token and invalidated when an unlike starts, so a slow recovery can no longer clobber the cache with a deleted tuple; (3) getPostLikes on v4 switches from paginateFetchAll (id-shaped startAfter cursors are rejected on indexOnly types) to terminal keyset pagination - live-verified shape: plain prefix query for page one (a terminal orderBy without a terminal clause is refused), prefix equality + ownerId-gt-last + orderBy terminal for later pages. Deferred with reasons on the PR: readback-timeout UI divergence (self-heals, budgets e2e-validated), unlike error asymmetry (pre-existing v2/v3 pattern). Validated: tsc clean, lint at baseline, v4 write suite 25/25 live on moutai. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Review triage complete (commit ce04f62). The independent migration review returned REQUIRES CHANGES with one HIGH and several lower findings; disposition: Fixed:
Deferred with reasons:
Validated after the fixes: tsc clean, lint at the exact baseline, v4 write suite 25/25 live on moutai. (Skipping a re-review loop on the 54-line fix commit itself: it implements the reviewer's own findings and was validated live.) 🤖 Posted autonomously by Claude on behalf of pasta. |
What
Phase 3 of PLAN_LIKE_OVERHAUL.md, stacked on #323 (merge that first; this PR retargets to staging automatically). Migrates the client to the v4 topology behind a new descriptor arm — v2/v3 behavior byte-identical — and cuts
yap.pr/devnetover to the v4 draft contract.lib/contract-topology.ts): indexOnly like shapes, inline hashtag, author fields; selected byNEXT_PUBLIC_CONTRACT_TOPOLOGY=v4.{postId, hashtag, postAuthor}(consensus-checked, 40127); confirmation viawaitForAffectedState(no get-by-id probes — nothing to get); unlike = delete-by-values with tuple recovery offbyAuthorTimePost+ a session tuple cache; every reported failure re-checked by readback (the SDK's post-broadcast-throw quirk). Liked-state, batched membership, and counts ride the same query shapes as v3 (they lower ontobyLiker/byPost).author+ first-hashtag; postHashtag writes/reads gated off under v4; tag pages ridepost.tagAndTime; trending deferred (empty state).ranked-likes.tsoverdocuments.ranked()(zero-count groups filtered) + the v4-only profile Top tab — the first proved top-K feature in the app..env.devnet→Aux325if…+v4(final commit). The final v4 re-registration (hashtag optional under upstream null-skip) comes later; this draft is the QA target.Validation (all live)
build, v4-local build,build:testinggreen.sensitive-content.spec.tsfailure was a pre-existing spec bug (reveal assertion filtered by the gate element that unmounts on Show; reproduced on the pristine base) — fixed here; that spec is now green on both networks for the first time.Notable decisions
Tombstones retain
author/hashtagverbatim (agreement-locked by existing likes); hashtag-validation recovery flow retired under v4 (no secondary write exists); cashtag pages empty under v4.🤖 Generated with Claude Code