diff --git a/app/src/agentworld/pages/FeedSection.test.tsx b/app/src/agentworld/pages/FeedSection.test.tsx index 628e34083..699c01332 100644 --- a/app/src/agentworld/pages/FeedSection.test.tsx +++ b/app/src/agentworld/pages/FeedSection.test.tsx @@ -583,6 +583,49 @@ describe('post composer', () => { }); }); + test('#4059: home feed requests includeSelf so the viewer sees their own posts', async () => { + const user = userEvent.setup(); + const myPostItem = { + post: { + ...samplePost, + postId: 'post-new', + body: 'My new post', + author: { ...sampleAuthor, cryptoId: MY_AGENT_ID, handle: MY_HANDLE }, + }, + score: 1, + reason: 'own', + }; + // First load: only a followed-agent post (no own posts). After the user + // composes, the refetch returns the followed post *and* their own one. + vi.mocked(apiClient.graphql.homeFeed) + .mockResolvedValueOnce({ items: [sampleFeedItem], count: 1 }) + .mockResolvedValue({ items: [sampleFeedItem, myPostItem], count: 2 }); + + render(); + const textarea = await screen.findByPlaceholderText(/what's on your mind/i); + + // Initial fetch must opt into own posts — otherwise a freshly composed post + // can never appear (the feed is followed-agents-only). + expect(vi.mocked(apiClient.graphql.homeFeed)).toHaveBeenCalledWith( + expect.objectContaining({ includeSelf: true }) + ); + + await user.type(textarea, 'My new post'); + await user.click(screen.getByRole('button', { name: /^post$/i })); + + // The created post now shows in the feed after the refetch. + await waitFor(() => { + expect(screen.getByText('My new post')).toBeInTheDocument(); + }); + + // Every home-feed request (mount + refetch) carries includeSelf:true. + const calls = vi.mocked(apiClient.graphql.homeFeed).mock.calls; + expect(calls.length).toBeGreaterThanOrEqual(2); + for (const call of calls) { + expect(call[0]).toMatchObject({ includeSelf: true }); + } + }); + test('Post button is disabled until a draft is entered', async () => { const user = userEvent.setup(); vi.mocked(apiClient.graphql.homeFeed).mockResolvedValue({ items: [sampleFeedItem], count: 1 }); diff --git a/app/src/agentworld/pages/FeedSection.tsx b/app/src/agentworld/pages/FeedSection.tsx index 51edc06f8..6353023d4 100644 --- a/app/src/agentworld/pages/FeedSection.tsx +++ b/app/src/agentworld/pages/FeedSection.tsx @@ -2,9 +2,11 @@ * FeedSection — Agent World "Feed" section. * * Renders the personalized home feed for the authenticated agent via - * `apiClient.graphql.homeFeed()` (GraphQL, requires unlocked wallet). - * Supports drill-down into individual posts (comments + likers) via - * `apiClient.graphql.post()`. + * `apiClient.graphql.homeFeed({ includeSelf: true })` (GraphQL, requires + * unlocked wallet). `includeSelf` is required so the viewer sees their own + * posts — without it the feed is followed-agents-only and a freshly composed + * post never shows up (#4059). Supports drill-down into individual posts + * (comments + likers) via `apiClient.graphql.post()`. * * Phase A interactive features (wallet-gated): * - Like / unlike toggle with optimistic update and server reconcile @@ -642,8 +644,13 @@ export default function FeedSection() { let cancelled = false; setFeedState({ status: 'loading' }); + // `includeSelf: true` — the personalized home feed otherwise returns only + // scored posts from *followed* agents, so the viewer's own posts (including + // one they just created via the composer) never appear. Without this the + // composer looks broken: Post succeeds server-side but the refetch can't + // show it (#4059). void apiClient.graphql - .homeFeed({ limit: 50 }) + .homeFeed({ limit: 50, includeSelf: true }) .then(result => { if (cancelled) return; const items = sortedHomeFeedItems(result); @@ -719,7 +726,7 @@ export default function FeedSection() { void apiClient.feeds .deletePost(post.postId) .then(() => { - void apiClient.graphql.homeFeed({ limit: 50 }).then(result => { + void apiClient.graphql.homeFeed({ limit: 50, includeSelf: true }).then(result => { const items = sortedHomeFeedItems(result); setFeedState({ status: 'ok', items }); }); @@ -730,7 +737,7 @@ export default function FeedSection() { // ── Refetch feed ─────────────────────────────────────────────────────────── const refetchFeed = () => { - void apiClient.graphql.homeFeed({ limit: 50 }).then(result => { + void apiClient.graphql.homeFeed({ limit: 50, includeSelf: true }).then(result => { const items = sortedHomeFeedItems(result); setFeedState({ status: 'ok', items }); });