Skip to content

fix(accounts): adapt 5chan to compact account history hooks#1118

Merged
tomcasaburi merged 3 commits intomasterfrom
codex/fix/account-history-performance
Mar 20, 2026
Merged

fix(accounts): adapt 5chan to compact account history hooks#1118
tomcasaburi merged 3 commits intomasterfrom
codex/fix/account-history-performance

Conversation

@tomcasaburi
Copy link
Copy Markdown
Member

@tomcasaburi tomcasaburi commented Mar 20, 2026

Adapt 5chan to the newer compact account-history hooks without changing user-visible behavior.

  • guard pending-comment lookups so routes can resolve before account data is ready
  • move (You), fresh replies, and recent local post injection onto narrower account-history lookups
  • pin 5chan to the updated hooks revision and cover the new paths with regression tests

Closes #1117


Note

Medium Risk
Touches many routes/components that read account comment history and changes how/when lookups are issued; mistakes could cause missing pending posts, incorrect “(You)” labels, or feed injection regressions. Scope is broad but largely refactors around safer parsing and narrower queries rather than new behavior.

Overview
Adapts account-history usage to the updated @bitsocialnet/bitsocial-react-hooks revision by introducing useSafeAccountComment and replacing direct useAccountComment calls across app layout, headers, boards bar, post views, and forms to avoid invalid indices/CID lookups before account data is ready.

Scopes account-history queries to reduce work: Board/Catalog now request only recent community-specific account posts for local feed injection, and useFreshReplies requests only indexed account comments; ReplyQuotePreview now determines “(You)” via a direct account-comment CID lookup before falling back to author-address matching.

Removes useCatalogFeedRows in favor of inline row chunking with a safe minimum column count, tightens /pending/:accountCommentIndex validation, and adds/updates regression tests to cover the new lookup paths. Also bumps Cursor agent configs to composer-2.

Written by Cursor Bugbot for commit a4af5b6. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • Bug Fixes

    • Safer handling and validation of account-comment inputs to reduce malformed pending-post and redirection errors.
    • More reliable pending-post and reply ownership detection.
  • Performance

    • Scoped account-comment queries by community and recent time window.
    • Added memoization to avoid unnecessary recalculations.
  • Refactor

    • Simplified catalog feed row logic for clearer feed processing.
  • Chores

    • Updated AI agent configurations to a newer model.
    • Updated an upstream package reference.
  • Tests

    • Expanded and hardened tests around account-comment lookups and quotelink ownership.

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
5chan Ready Ready Preview, Comment Mar 20, 2026 1:14pm

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 20, 2026

📝 Walkthrough

Walkthrough

This PR migrates account-comment lookups to guarded, queryable patterns: introduces useSafeAccountComment, scopes useAccountComments calls with targeted options, updates components to use the safe hook, adjusts tests/mocks accordingly, removes useCatalogFeedRows, updates a dependency tarball, and bumps several agent models to composer-2.

Changes

Cohort / File(s) Summary
Agent Model Updates
\.cursor/agents/browser-check.md, \.cursor/agents/code-quality.md, \.cursor/agents/plan-implementer.md, \.cursor/agents/react-doctor-fixer.md, \.cursor/agents/react-patterns-enforcer.md, \.cursor/agents/translator.md
Switched agent front-matter model from composer-1.5composer-2 in each agent file (no workflow changes).
New Safe Hook
src/hooks/use-safe-account-comment.ts
Added useSafeAccountComment default export: normalizes/validates commentIndex, conditionally forwards commentIndex or commentCid to useAccountComment, or uses sentinel { commentIndex: -1 } when no valid input/account.
Safe Hook Tests
src/hooks/__tests__/use-safe-account-comment.test.tsx
New comprehensive tests validating sentinel lookups, string→number normalization, malformed-index fallback, and commentCid passthrough once account exists.
Account-Comments Scoping & Fresh Replies
src/hooks/use-fresh-replies.ts, src/hooks/use-catalog-feed-rows.ts
useFreshReplies: derive numeric reply indices and pass commentIndices (or sentinel) to useAccountComments; useCatalogFeedRows hook removed (feed-row logic inlined elsewhere).
Component Hook Migrations
src/app.tsx, src/components/.../board-buttons.tsx, src/components/.../board-header.tsx, src/components/.../boards-bar.tsx, src/components/.../post-desktop.tsx, src/components/.../post-form.tsx, src/components/.../post-mobile.tsx, src/views/pending-post/pending-post.tsx, src/hooks/use-theme.ts
Replaced useAccountComment usages with useSafeAccountComment, removed as any casts, added explicit numeric parsing where appropriate, and adjusted imports.
Quote Preview Ownership Detection
src/components/reply-quote-preview/reply-quote-preview.tsx, src/components/reply-quote-preview/__tests__/reply-quote-preview.test.tsx
Replaced broad useAccountComments scan with useIsOwnQuotelink that prefers useSafeAccountComment by CID and falls back to useAccount().author.address; tests updated to exercise new lookup behavior and call recording.
Board & Catalog Account-Comments Scoping
src/views/board/board.tsx, src/views/catalog/catalog.tsx, src/views/catalog/__tests__/catalog.test.tsx, src/views/board/__tests__/board.test.tsx
Scoped useAccountComments calls by communityAddress, newerThan (RECENT_ACCOUNT_COMMENT_WINDOW_SECONDS = 3600), and sortType; tests updated to track and assert passed options and scoped results.
Tests: useAccount mock additions & call tracking
src/components/.../__tests__/*, src/hooks/__tests__/use-fresh-replies.test.tsx, src/views/pending-post/__tests__/pending-post.test.tsx
Added useAccount mock (returns undefined) across several test suites; extended useAccountComments mocks to accept and record scoping params (commentIndices, communityAddress, newerThan, sortType) and added assertions for parameter usage and redirect behavior.
Dependency update
package.json
Updated @bitsocialnet/bitsocial-react-hooks tarball URL to a new commit hash.
Removed export
src/hooks/use-catalog-feed-rows.ts
Deleted useCatalogFeedRows default export and implementation (feed-row generation relocated/inlined).

Sequence Diagram(s)

sequenceDiagram
    participant Component
    participant useSafeAccountComment
    participant useAccount
    participant useAccountComment
    participant Fallback as AuthorCheck

    rect rgba(100,150,200,0.5)
    Note over Component,useSafeAccountComment: Safe account-comment lookup flow
    Component->>useSafeAccountComment: call({ commentIndex? / commentCid? })
    useSafeAccountComment->>useAccount: get account
    alt valid commentIndex
        useSafeAccountComment->>useAccountComment: call({ commentIndex: normalized })
        useAccountComment-->>useSafeAccountComment: account comment | empty
    else commentCid && account exists
        useSafeAccountComment->>useAccountComment: call({ commentCid })
        useAccountComment-->>useSafeAccountComment: account comment | empty
    else no valid input/account
        useSafeAccountComment->>useAccountComment: call({ commentIndex: -1 })
        useAccountComment-->>useSafeAccountComment: sentinel empty
    end
    useSafeAccountComment-->>Component: return result
    end
Loading
sequenceDiagram
    participant QuoteComponent
    participant useSafeAccountComment
    participant useAccount
    participant Fallback as AuthorCheck

    rect rgba(200,150,100,0.5)
    Note over QuoteComponent,useSafeAccountComment: Quote-preview ownership check
    QuoteComponent->>useSafeAccountComment: lookup by quotelink.cid
    useSafeAccountComment->>useAccount: get account
    useSafeAccountComment->>useSafeAccountComment: attempt CID lookup (delegates to useAccountComment)
    alt found matching account comment
        useSafeAccountComment-->>QuoteComponent: isOwn = true
    else not found
        QuoteComponent->>Fallback: compare quotelink.author.address vs useAccount().author.address
        Fallback-->>QuoteComponent: isOwn = result
    end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hop with care, no broad-scan fright,

Scoped lookups keep the answers light.
CIDs checked first, fallbacks in view,
Composer upgraded, dependency too.
A tidy burrow—safe, swift, and new.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main objective: adapting 5chan to compact account-history hooks. It is specific, concise, and directly reflects the changeset's core purpose.
Linked Issues check ✅ Passed The PR fully addresses issue #1117 by introducing useSafeAccountComment for guarded pending-comment handling, narrowing account-history queries for hot UI surfaces, and preventing crashes from invalid lookups before account availability.
Out of Scope Changes check ✅ Passed All changes directly support the core objectives: agent config updates (composer-2 migration), dependency version bump, test infrastructure updates, and hook implementations align with the guarded lookup and performance optimization goals.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fix/account-history-performance
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can generate a title for your PR based on the changes with custom instructions.

Set the reviews.auto_title_instructions setting to generate a title for your PR based on the changes in the PR with custom instructions.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Comment thread src/views/catalog/__tests__/catalog.test.tsx
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
src/views/catalog/catalog.tsx (1)

286-297: Consider extracting the recent-account injection logic into a shared hook.

This scoped lookup/filter block now matches src/views/board/board.tsx almost line-for-line. Pulling it into src/hooks/ would keep the sentinel lookup, one-hour window, and post-only filter from drifting between the two views.

As per coding guidelines, "Avoid copy-paste logic across components. Extract custom hooks in src/hooks/."

Also applies to: 303-331

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/views/catalog/catalog.tsx` around lines 286 - 297, The recent-account
lookup/filter (accountCommentLookupOptions + useAccountComments usage) is
duplicated with board.tsx; extract this logic into a shared hook (e.g.,
useRecentAccountComments) under src/hooks/ that encapsulates the sentinel
lookup, RECENT_ACCOUNT_COMMENT_WINDOW_SECONDS, post-only filtering and returns
the same shape used now (e.g., { accountComments }). Replace the inline
accountCommentLookupOptions and direct useAccountComments calls in catalog.tsx
(and board.tsx) with the new hook, reusing EMPTY_ACCOUNT_COMMENT_LOOKUP and
useAccountComments inside the hook to preserve behavior and dependencies
(communityAddress).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.cursor/agents/plan-implementer.md:
- Line 3: Update the Codex agent configuration so the model value matches the
Cursor change: open plan-implementer.toml and replace the existing model =
"gpt-5.3-codex" entry with model = "composer-2" (preserve TOML formatting and
quoting). Ensure there are no duplicate model keys and save the file so both
agent toolchains use the same model name.

In `@src/components/reply-quote-preview/reply-quote-preview.tsx`:
- Around line 84-89: The ownership check in useIsOwnQuotelink is too permissive;
change the logic to require an exact cid match first (ownQuotelink?.cid ===
quotelinkReply?.cid) and only fall back to comparing author addresses when BOTH
addresses are present (ownQuotelink?.author?.address &&
quotelinkReply?.author?.address) before checking equality; reference the
useIsOwnQuotelink function and the quotelinkReply, ownQuotelink, and account
symbols when making this change.

In `@src/views/catalog/catalog.tsx`:
- Around line 443-453: The rows useMemo can hang when columnCount is 0; before
chunking processedFeed in the loop inside the rows useMemo (which uses
columnCount, isFeedLoaded, processedFeed), clamp the step to at least 1 (e.g.,
const step = Math.max(1, columnCount)) and use that step in the for loop and
slice calls so you never do i += 0 and the render cannot enter an infinite loop.

In `@src/views/pending-post/pending-post.tsx`:
- Around line 12-13: Pass the raw accountCommentIndex string directly into
useSafeAccountComment instead of parsing it—remove the parseInt usage that sets
commentIndex and instead forward accountCommentIndex to useSafeAccountComment
(the hook accepts both string and number and performs strict normalization);
additionally, update the hook's boundary check from allowing indices <=
accountComments.length to strictly < accountComments.length so out-of-range
(equal-to-length) indices are rejected.

---

Nitpick comments:
In `@src/views/catalog/catalog.tsx`:
- Around line 286-297: The recent-account lookup/filter
(accountCommentLookupOptions + useAccountComments usage) is duplicated with
board.tsx; extract this logic into a shared hook (e.g.,
useRecentAccountComments) under src/hooks/ that encapsulates the sentinel
lookup, RECENT_ACCOUNT_COMMENT_WINDOW_SECONDS, post-only filtering and returns
the same shape used now (e.g., { accountComments }). Replace the inline
accountCommentLookupOptions and direct useAccountComments calls in catalog.tsx
(and board.tsx) with the new hook, reusing EMPTY_ACCOUNT_COMMENT_LOOKUP and
useAccountComments inside the hook to preserve behavior and dependencies
(communityAddress).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cc5ee1ed-97b9-44e2-9fd4-d9b83490a251

📥 Commits

Reviewing files that changed from the base of the PR and between 4ec74bc and 052af1b.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (30)
  • .cursor/agents/browser-check.md
  • .cursor/agents/code-quality.md
  • .cursor/agents/plan-implementer.md
  • .cursor/agents/react-doctor-fixer.md
  • .cursor/agents/react-patterns-enforcer.md
  • .cursor/agents/translator.md
  • package.json
  • src/app.tsx
  • src/components/board-buttons/__tests__/board-buttons.test.tsx
  • src/components/board-buttons/board-buttons.tsx
  • src/components/board-header/__tests__/board-header.test.tsx
  • src/components/board-header/board-header.tsx
  • src/components/boards-bar/__tests__/boards-bar.test.tsx
  • src/components/boards-bar/boards-bar.tsx
  • src/components/post-desktop/post-desktop.tsx
  • src/components/post-form/post-form.tsx
  • src/components/post-mobile/post-mobile.tsx
  • src/components/reply-quote-preview/__tests__/reply-quote-preview.test.tsx
  • src/components/reply-quote-preview/reply-quote-preview.tsx
  • src/hooks/__tests__/use-fresh-replies.test.tsx
  • src/hooks/__tests__/use-safe-account-comment.test.tsx
  • src/hooks/use-fresh-replies.ts
  • src/hooks/use-safe-account-comment.ts
  • src/hooks/use-theme.ts
  • src/views/board/__tests__/board.test.tsx
  • src/views/board/board.tsx
  • src/views/catalog/__tests__/catalog.test.tsx
  • src/views/catalog/catalog.tsx
  • src/views/pending-post/__tests__/pending-post.test.tsx
  • src/views/pending-post/pending-post.tsx

---
name: plan-implementer
model: composer-1.5
model: composer-2
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read-only verification for model/config consistency across Cursor and Codex surfaces.

set -euo pipefail

echo "== Agent files still on composer-1.5 (if any) =="
rg -n --glob '.cursor/agents/**' --glob '.codex/agents/**' '^\s*model:\s*composer-1\.5\s*$' || true

echo
echo "== Agent files on composer-2 =="
rg -n --glob '.cursor/agents/**' --glob '.codex/agents/**' '^\s*model:\s*composer-2\s*$' || true

echo
echo "== Entry points referencing model/agent orchestration =="
fd 'config\.toml$|hooks\.json$' .codex .cursor 2>/dev/null | xargs -r -I{} sh -c 'echo "--- {}"; rg -n "composer|agent|hook|model" "{}" || true'

Repository: bitsocialnet/5chan

Length of output: 2364


🏁 Script executed:

#!/bin/bash

echo "=== Finding all agent files ==="
fd . .cursor/agents .codex/agents 2>/dev/null | sort

echo
echo "=== Checking plan-implementer files ==="
fd 'plan-implementer' .cursor .codex 2>/dev/null

echo
echo "=== Content of .cursor/agents/plan-implementer.md (if exists) ==="
if [ -f ".cursor/agents/plan-implementer.md" ]; then
  cat -n ".cursor/agents/plan-implementer.md"
fi

echo
echo "=== Content of .codex/agents/plan-implementer.toml (if exists) ==="
if [ -f ".codex/agents/plan-implementer.toml" ]; then
  cat -n ".codex/agents/plan-implementer.toml"
fi

echo
echo "=== All model specifications in cursor and codex agent files ==="
rg -n 'model\s*[:=]' .cursor/agents/ .codex/agents/ 2>/dev/null || true

Repository: bitsocialnet/5chan

Length of output: 5439


Update .codex/agents/plan-implementer.toml to match the model change in .cursor/agents/plan-implementer.md.

The .cursor/ agent was updated to composer-2, but .codex/agents/plan-implementer.toml still specifies model = "gpt-5.3-codex". Both toolchain implementations must use the same model to avoid split behavior. Update the Codex side to align with the Cursor change.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/agents/plan-implementer.md at line 3, Update the Codex agent
configuration so the model value matches the Cursor change: open
plan-implementer.toml and replace the existing model = "gpt-5.3-codex" entry
with model = "composer-2" (preserve TOML formatting and quoting). Ensure there
are no duplicate model keys and save the file so both agent toolchains use the
same model name.

Comment thread src/components/reply-quote-preview/reply-quote-preview.tsx
Comment thread src/views/catalog/catalog.tsx
Comment thread src/views/pending-post/pending-post.tsx Outdated
@tomcasaburi
Copy link
Copy Markdown
Member Author

Addressed the valid review findings in a4af5b623.

Fixed:

  • tightened (You) detection so CID matches must be exact and author fallback only runs when both addresses exist
  • clamped catalog row chunking so very narrow viewports cannot hit i += 0
  • made pending-post validation strict for malformed and out-of-range indices, while passing the raw route param through useSafeAccountComment
  • removed the now-dead use-catalog-feed-rows hook and the stale catalog test mock

Declined:

  • the CodeRabbit composer-2 comment on .codex is not applicable here; .cursor is intentionally on composer-2, while .codex uses Codex models and should not be changed to a Cursor-only model name

Local verification after the fixes:

  • yarn prettier
  • yarn build
  • yarn type-check
  • yarn test
  • focused Vitest run for the touched account-history tests

yarn lint and yarn doctor still report the repo's existing warning backlog, but no new blocking errors from this change.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/views/pending-post/pending-post.tsx`:
- Around line 20-25: The validation currently treats an empty accountComments
array as "OK" which lets any non‑negative index pass; change the logic in
isValidAccountCommentIndex to only allow the escape when the account comments
are truly not yet loaded (e.g., accountComments == null/undefined) instead of
when accountComments.length === 0. Specifically, update the condition that
references accountComments?.length === 0 so it checks for an explicit "not
ready" state (accountComments == null) and otherwise enforce
normalizedAccountCommentIndex < accountComments.length; keep the other checks
(accountCommentIndex falsy, hasNormalizedAccountCommentIndex, Number.isInteger)
unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6be25f90-c63d-4c2f-b1d2-63af214610b8

📥 Commits

Reviewing files that changed from the base of the PR and between 052af1b and a4af5b6.

📒 Files selected for processing (8)
  • src/components/reply-quote-preview/__tests__/reply-quote-preview.test.tsx
  • src/components/reply-quote-preview/reply-quote-preview.tsx
  • src/hooks/__tests__/use-safe-account-comment.test.tsx
  • src/hooks/use-catalog-feed-rows.ts
  • src/views/catalog/__tests__/catalog.test.tsx
  • src/views/catalog/catalog.tsx
  • src/views/pending-post/__tests__/pending-post.test.tsx
  • src/views/pending-post/pending-post.tsx
💤 Files with no reviewable changes (1)
  • src/hooks/use-catalog-feed-rows.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/components/reply-quote-preview/tests/reply-quote-preview.test.tsx
  • src/components/reply-quote-preview/reply-quote-preview.tsx
  • src/views/pending-post/tests/pending-post.test.tsx
  • src/views/catalog/catalog.tsx
  • src/views/catalog/tests/catalog.test.tsx

Comment on lines 20 to +25
const isValidAccountCommentIndex =
!accountCommentIndex ||
(!isNaN(parseInt(accountCommentIndex)) &&
parseInt(accountCommentIndex) >= 0 &&
Number.isInteger(parseFloat(accountCommentIndex)) &&
(accountComments?.length === 0 || parseInt(accountCommentIndex) <= accountComments.length));
(hasNormalizedAccountCommentIndex &&
normalizedAccountCommentIndex >= 0 &&
Number.isInteger(normalizedAccountCommentIndex) &&
(accountComments?.length === 0 || normalizedAccountCommentIndex < accountComments.length));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

An empty history still bypasses the out-of-range check.

Line 25 makes every non-negative integer valid whenever accountComments.length === 0, so a loaded account with no comments will never send /pending-post/0 or /pending-post/999 to /not-found. Please gate that escape hatch on an explicit “account not ready” condition instead of the array being empty.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/views/pending-post/pending-post.tsx` around lines 20 - 25, The validation
currently treats an empty accountComments array as "OK" which lets any
non‑negative index pass; change the logic in isValidAccountCommentIndex to only
allow the escape when the account comments are truly not yet loaded (e.g.,
accountComments == null/undefined) instead of when accountComments.length === 0.
Specifically, update the condition that references accountComments?.length === 0
so it checks for an explicit "not ready" state (accountComments == null) and
otherwise enforce normalizedAccountCommentIndex < accountComments.length; keep
the other checks (accountCommentIndex falsy, hasNormalizedAccountCommentIndex,
Number.isInteger) unchanged.

@tomcasaburi tomcasaburi merged commit c2e8e16 into master Mar 20, 2026
11 checks passed
@tomcasaburi tomcasaburi deleted the codex/fix/account-history-performance branch March 20, 2026 13:25
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.

5chan still broad-scans account history and crashes on guarded pending-comment routes

1 participant