Skip to content

fix(facebook/feed): obtain the home feed landmark instead of re-navigating - #2

Merged
lawmight merged 1 commit into
lawmight/fb-chrome-stackfrom
cursor/facebook-feed-landmark-469a
Sep 5, 2026
Merged

lawmight merged 1 commit into
lawmight/fb-chrome-stackfrom
cursor/facebook-feed-landmark-469a

Conversation

@lawmight

@lawmight lawmight commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Description

Follow-up to #1. After that merge, live smoke on tom.coustols correctly refused the Messenger bleed but never obtained a feed landmark:

message: facebook feed news-feed surface did not render
help: Surface diagnostics: path=/, feedFound=no, messengerDom=yes.

Reading the surface loop against those values, three defects explain it:

  1. Re-navigation reset hydration. ensureNewsFeedSurface ran goto on every attempt (4× with ~5s settle). Facebook home under the Shifter PAC proxy hydrates slower than that, so the feed column could never appear before the next goto threw it away.
  2. messengerDom=yes was a false positive. The check matched [aria-label*="Messenger"] / [aria-label*="Chat"], which hits the top-nav Messenger icon present on every facebook.com page. It did not prove embedded chat.
  3. Readiness demanded role=feed only. This repo's own [autofix] facebook/feed: COMMAND_EXEC jackwener/OpenCLI#2089 fix documents that modern FB home variants drop the article/feed wrappers. Those variants mark posts with data-pagelet="FeedUnit_n", aria-posinset, and per-post "Actions for this post" menus. A strict role=feed requirement can never succeed there.

Related issue: facebook feed Messenger bleed / no [role=feed] on home (jackwener#2453 stack)

Type of Change

  • 🐛 Bug fix

What changed

Surface acquisition (ensureNewsFeedSurface)

  • Navigate once (cache-busted home URL), then poll the same document up to 30s at 1.5s intervals. Bounded by poll count as well as wall clock.
  • Re-navigate at most once, and only if the document lands on a /messages route.
  • After 9s with no landmark, click the banner Home control once (EN/FR/ZH labels, href="/" fallback) to nudge the SPA.
  • Each poll globally closes docked chat windows (Close chat / Fermer la discussion / 关闭聊天) and presses dialogs' own Close button. Never touches accept/allow buttons.

Landmark detection (shared by probe + extractor via FEED_DOM_HELPERS)

  • landmarkrole-feed | feed-units (data-pagelet^=FeedUnit, aria-posinset) | post-menus | null
  • Chat chrome = docked chats, chat sidebar, Conversation with … panes, ChatTab/Messenger pagelets — excluding role=banner/navigation. Anything in banner/nav/complementary is never a post source.
  • On facebook.com home with no landmark, extraction still refuses (no_feed). No regression to exit 0 with blank-author chat rows; rowLooksLikeMessengerBleed post-filter kept.

Lazy-load scroll

  • Scroll the window as well as the landmark element (the home feed scrolls with the window; role=feed is not a scroll container — the previous commit had removed this).

Diagnostics for the next round

Failure hint now reports: landmark, roleFeed, feedUnits, postMenus, articles, chatChrome, mainTextLength, visibility, readyState, dialogs, and de-numbered pagelets (e.g. FeedUnit_n,LeftRail,ChatTab). These are structural only — no user content.

Tests

npm test -- clis/facebook/feed.test.js42 passed (all 5 Facebook suites: 102 passed). New cases:

  • navigates once and polls until feed-units hydrates (asserts goto called exactly once)
  • Home nudge fires exactly once after the threshold, never re-navigates
  • redirects home at most once from a /messages route
  • top-nav Messenger icon ⇒ messengerDom=false; docked chat ⇒ flagged but does not block readiness
  • FeedUnit / post-menu landmarks accepted without role=feed; menus inside chat chrome ignored
  • extracts a FeedUnit post with author on home while a docked "Teiki"-style thread is present (no bleed)
  • prepare step clicks Close chat + dialog Close only, never Allow all cookies
  • failure hint contains landmark=none, visibility=hidden, pagelets=…, chatChrome=…

Checklist

  • I ran the checks relevant to this PR
  • I updated tests or docs if needed
  • Live smoke on tom.coustols after merge

Expected live outcomes and next diagnostic

Result Meaning
Rows with authors Landmark obtained (any of the three kinds); fixed.
Error, hint shows pagelets=…FeedUnit_n… but landmark=none FB renamed markers; the pagelet list tells us the new anchor.
Error, visibility=hidden Background window is starving hydration; retry with --window foreground (or set defaultWindowMode: 'foreground' on the command).
Error, dialogs=[…] A modal (consent/notifications) is blocking; its label identifies which.
Error, mainTextLength small, readyState=complete FB served a stripped home for this session; next step is a browser snapshot of role=main.
Open in Web Open in Cursor 

Summary by Sourcery

Fix Facebook feed acquisition and extraction so slowly hydrated home feeds are detected without re-navigation or Messenger content bleed.

Bug Fixes:

  • Prevent Facebook feed hydration from being reset by repeatedly navigating while waiting for the home feed to render.
  • Recognize modern Facebook feed landmarks beyond role=feed and avoid mistaking top-navigation Messenger controls for embedded chat.
  • Prevent Messenger and docked-chat content from being extracted as feed posts.

Enhancements:

  • Add bounded feed surface polling with a single Home navigation nudge and at most one redirect from Messenger routes.
  • Improve feed loading by scrolling both the page and feed container and provide structural surface diagnostics for failures.

Tests:

  • Expand Facebook feed coverage for slow hydration, alternate landmarks, chat filtering, navigation behavior, preparation actions, and diagnostics.

Summary by cubic

Fixes the facebook feed surface loop so it reliably obtains the home feed landmark, instead of re-navigating every ~5s and resetting Facebook's slow hydration under the proxy. This addresses the Messenger bleed / no [role=feed] on home issue (jackwener#2453 stack).

Bug Fixes

  • Navigates once (cache-busted home URL) and polls the same document up to 30s; re-navigates at most once, only from /messages routes.
  • Accepts role=feed, FeedUnit pagelets, aria-posinset posts, or per-post action menus as the landmark, matching modern home variants (see [autofix] facebook/feed: COMMAND_EXEC jackwener/OpenCLI#2089).
  • Chat chrome now means docked chats, chat sidebar, and thread panes only — the top-nav Messenger icon is no longer a false positive.
  • Each poll closes docked chats and dialog Close buttons (never accept/allow buttons); the banner Home control nudges the SPA once after 9s, and the window is scrolled for lazy posts.
  • Failure hints report structural diagnostics (landmark, pagelets, visibility, dialogs).
  • 42 tests pass in clis/facebook/feed.test.js (102 across all 5 Facebook suites); extraction still refuses on home with no landmark.

Written for commit 5b8a6b9. Summary will update on new commits.

Review in cubic

…ating

Live smoke after the anti-bleed gate: path=/, feedFound=no, messengerDom=yes,
exit 1. Three causes in the surface loop, all fixed here:

- The loop re-ran goto on every attempt (4x ~5s). Facebook home under the
  Shifter proxy hydrates slower than that, and every re-navigation reset it.
  Navigate once, then poll the same document for up to 30s (bounded by poll
  count too, so mocked/broken timers cannot spin).
- messengerDom matched the top-nav Messenger icon present on every FB page,
  so it was a false positive. Chat chrome now means docked chats, chat
  sidebar, and thread panes outside role=banner/navigation.
- Readiness required role=feed only. Modern home variants (see jackwener#2089) mark
  posts with data-pagelet=FeedUnit_n / aria-posinset / per-post action menus.
  Accept those as landmarks; on home with no landmark at all still refuse.

Also: globally close docked chat windows and dialog Close buttons (never
accept buttons), nudge the SPA via the banner Home control once after 9s,
scroll the window (not just role=feed) so lazy posts stream, and emit
structural diagnostics (landmark, counts, pagelet names, visibilityState,
dialogs) in the failure hint for the next round.

Co-authored-by: Tom Coustols <tom.coustols@tcdynamics.fr>
@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 8ed1593a-a91b-4d4a-a7f8-04653372fab2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

❤️ Share

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

@sourcery-ai

sourcery-ai Bot commented Sep 5, 2026

Copy link
Copy Markdown

Reviewer's Guide

The PR replaces repeated Facebook feed re-navigation with bounded same-document polling and targeted SPA recovery, introduces shared structural landmark/chat classification for modern home layouts, preserves extraction safety against Messenger bleed, improves lazy loading and diagnostics, and adds comprehensive regression coverage.

Sequence diagram for Facebook feed surface acquisition

sequenceDiagram
    participant FeedCommand
    participant BrowserPage
    participant FacebookHome

    FeedCommand->>BrowserPage: goto(feedNavigationUrl)
    loop Poll until ready or timeout
        FeedCommand->>BrowserPage: evaluate(buildPrepareFeedScript)
        BrowserPage->>FacebookHome: Close docked chats and dialog Close controls
        alt Messages route
            BrowserPage->>FacebookHome: location.assign(FACEBOOK_HOME)
            FeedCommand->>BrowserPage: goto(feedNavigationUrl) once
        else No landmark after threshold
            BrowserPage->>FacebookHome: Click Home control once
        end
        FeedCommand->>BrowserPage: evaluate(buildSurfaceCheckScript)
        BrowserPage-->>FeedCommand: landmark or diagnostics
        alt landmark found
            FeedCommand-->>FeedCommand: Continue to extraction
        else Not ready
            FeedCommand->>BrowserPage: sleep(pollMs)
        end
    end
Loading

Flow diagram for Facebook feed landmark classification

flowchart TD
    A[Inspect Facebook DOM] --> B{role=feed outside chat chrome?}
    B -->|Yes| C[landmark = role-feed]
    B -->|No| D{FeedUnit or aria-posinset outside chat chrome?}
    D -->|Yes| E[landmark = feed-units]
    D -->|No| F{Post action menu in feed column?}
    F -->|Yes| G[landmark = post-menus]
    F -->|No| H[landmark = null]
    C --> I[Surface ready]
    E --> I
    G --> I
    H --> J[Home extraction returns no_feed]
Loading

File-Level Changes

Change Details Files
Reworked feed surface acquisition to preserve slow Facebook hydration while handling Messenger-route redirects and SPA nudging.
  • Navigate to the cache-busted home URL once, then poll the same document for up to 30 seconds with bounded timing.
  • Allow one redirect back to home when landing on a messages route.
  • Click localized Home navigation once after the hydration threshold and close docked chats or dialog Close controls during preparation.
clis/facebook/feed.js
Unified structural feed and chat detection across probing and extraction to support modern Facebook home variants without Messenger bleed.
  • Share DOM helpers that classify role=feed, FeedUnit/aria-posinset markers, and post action menus as feed landmarks.
  • Exclude banner/navigation and chat chrome from post sources while no longer treating the top-nav Messenger icon as embedded chat.
  • Require a landmark on the home route and retain Messenger-bleed post filtering.
clis/facebook/feed.js
Improved lazy loading and failure diagnostics for feed acquisition.
  • Scroll both the landmark/root and the window to trigger home-feed lazy loading.
  • Report structural state such as landmark type, marker counts, chat chrome, visibility, dialogs, ready state, and normalized pagelets.
clis/facebook/feed.js
Expanded Facebook feed tests around hydration timing, landmark variants, chat isolation, preparation safety, and diagnostics.
  • Verify single navigation, polling, one-time Home nudging, and at-most-once messages-route recovery.
  • Cover top-nav versus docked Messenger detection, FeedUnit and post-menu landmarks, chat exclusion, and FeedUnit extraction.
  • Ensure only chat/dialog Close controls are clicked and structural failure hints are emitted.
clis/facebook/feed.test.js

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@lawmight
lawmight merged commit a453f71 into lawmight/fb-chrome-stack Sep 5, 2026
3 checks passed

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="clis/facebook/feed.js" line_range="92-93" />
<code_context>
+      return document.querySelector('[role="main"]');
+    }
+    function feedLandmarkEl() {
+      return document.querySelector('[role="main"] [role="feed"]') || document.querySelector('[role="feed"]');
+    }
+    function postMenuEls() {
+      const main = mainEl();
</code_context>
<issue_to_address>
**issue (bug_risk):** `feedLandmarkEl` accepts any `[role="feed"]` in the document, including a feed-like region nested under `role=banner`, `navigation`, or `complementary`. That region makes the surface ready and becomes the extraction root, so navigation/sidebar content is treated as the news feed.

**Triggers:** When Facebook renders a role-feed-like region outside the main feed column.

**Suggested fix:** Require the matched element to be outside `OUTSIDE_FEED_ROLES` and, preferably, contained by `[role="main"]` before accepting it as a landmark.

```suggestion
      const feeds = Array.from(document.querySelectorAll('[role="feed"]'));
      return feeds.find((el) => !isOutsideFeedColumn(el) && el.closest('[role="main"]'))
        || feeds.find((el) => !isOutsideFeedColumn(el));
    }
```
</issue_to_address>

### Comment 2
<location path="clis/facebook/feed.js" line_range="37-39" />
<code_context>
-  }
-  // Top-level feed posts should carry an author or engagement metrics. Authorless
-  // metric-less rows are extraction garbage, commonly Messenger/thread bleed.
+  // Top-level feed posts carry an author or engagement metrics. Authorless,
+  // metric-less rows are extraction garbage — typically docked-chat bleed.
   return true;
 }

</code_context>
<issue_to_address>
**issue (broader_impact):** Every nonempty row whose author is not extracted and whose three engagement fields are `'-'` is classified as Messenger bleed and discarded or causes the command to fail. A legitimate feed post with an unrecognized author markup and no visible engagement counts therefore cannot be returned, even when its content came from a validated feed landmark.

**Triggers:** When a real post has no engagement metrics and `findAuthor` cannot recognize its author markup.

**Suggested fix:** Retain the stronger Messenger-specific text/container evidence from the old check, or only classify an authorless metric-less row as bleed when its content also matches chat markers or its DOM container is chat chrome.
</issue_to_address>

Sourcery assessment

Approval pending. 2 findings to address first.

Blocking findings: clis/facebook/feed.js:93, clis/facebook/feed.js:39


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread clis/facebook/feed.js
Comment on lines +92 to +93
return document.querySelector('[role="main"] [role="feed"]') || document.querySelector('[role="feed"]');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): feedLandmarkEl accepts any [role="feed"] in the document, including a feed-like region nested under role=banner, navigation, or complementary. That region makes the surface ready and becomes the extraction root, so navigation/sidebar content is treated as the news feed.

Triggers: When Facebook renders a role-feed-like region outside the main feed column.

Suggested fix: Require the matched element to be outside OUTSIDE_FEED_ROLES and, preferably, contained by [role="main"] before accepting it as a landmark.

Suggested change
return document.querySelector('[role="main"] [role="feed"]') || document.querySelector('[role="feed"]');
}
const feeds = Array.from(document.querySelectorAll('[role="feed"]'));
return feeds.find((el) => !isOutsideFeedColumn(el) && el.closest('[role="main"]'))
|| feeds.find((el) => !isOutsideFeedColumn(el));
}

Comment thread clis/facebook/feed.js
Comment on lines +37 to 39
// Top-level feed posts carry an author or engagement metrics. Authorless,
// metric-less rows are extraction garbage — typically docked-chat bleed.
return true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (broader_impact): Every nonempty row whose author is not extracted and whose three engagement fields are '-' is classified as Messenger bleed and discarded or causes the command to fail. A legitimate feed post with an unrecognized author markup and no visible engagement counts therefore cannot be returned, even when its content came from a validated feed landmark.

Triggers: When a real post has no engagement metrics and findAuthor cannot recognize its author markup.

Suggested fix: Retain the stronger Messenger-specific text/container evidence from the old check, or only classify an authorless metric-less row as bleed when its content also matches chat markers or its DOM container is chat chrome.

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.

2 participants