Files
edgeever/docs/browser-clipper-platforms.md
T

63 KiB
Raw Blame History

Browser platform clips

简体中文

Related to Issue #493 and the implementation plan. Updated: 2026-10-15. Phase 1 is merged; Phase 2 and the remaining requested adapters are implemented locally; extension-store publication and full cross-browser live acceptance remain pending.

2026-10-15 PR submission verification

This submission uses latest upstream 72ab4816 and includes P2/follow-up article adapters plus repairs to merged P1. Upstream note duplication merges cleanly with the Web changes. This submission includes only the 83 task files; unrelated Android caches are excluded.

After integration, 3,529 bulk tests, 17 API integrations and 13 desktop authentication integrations pass: 3,559 total, including 427 extension tests. Root/mobile typechecking, Web and Chromium/Firefox extension builds pass; Firefox lint reports 0 errors, 0 notices and 7 dependency warnings. The 31-source Chromium save/attachment-readback flow and two HTML safety checks pass. Blank-line whitespace cleanup preserves the complete extraction results and preformatted text in all six affected fixtures; 67 related tests pass.

The first browser rerun finds a stale local Wrangler asset manifest after rebuilding Web: new JavaScript paths return HTML. Restarting this task's local development service restores the correct MIME types and the complete regression passes. Production code and test timeouts are unchanged. Post-test API/backup ID comparison confirms that all original 17 notes and one token remain.

This is a staged contribution associated with #493. Store publication, full-content acceptance of the current login-truncated BOSS page and native Edge/Firefox saving remain pending. Older statements such as “not committed” below describe their respective review rounds.

2026-10-15 Save and text fidelity review

This pass fixes six reproduced defects:

  • Sspai authors come only from the current article, retaining coauthors and optional absence while excluding unrelated or hidden author cards.
  • An odd number of backslashes before a pipe in table code no longer splits columns or drops later cells. Fragments that GFM cannot represent losslessly use escaped plain text, preserving characters and cell boundaries; other code styling remains.
  • Image archival rewriting preserves title entities, line breaks and table pipes, preventing lost images or shifted columns after upload.
  • Platform context menus fix the selected permalink before showing saving feedback, so another right-click during feedback injection cannot replace the target.
  • Generic, platform and feed toolbar saves record the initial selection and whole-page mode before joining the queue; selection menus use the browser-provided original text. Changed or lost selections save only the original plain text, while matching selections retain rich content and pictures. Plain-text fallback uses character entities to avoid reinterpreting headings, indentation, URLs or HTML. Navigation still stops saving. Login pages and lists without an initial selection never fall back to whole-page capture.
  • Selection-menu saving no longer globally compresses blank lines, preserving consecutive blank lines inside code.

The final full non-E2E run passes 3,505 bulk tests (including 427 extension tests), 17 API integrations and 13 desktop authentication integrations: 3,535 total. Root/mobile typechecking, Web and Chromium/Firefox extension builds pass; Firefox lint reports 0 errors, 0 notices and 7 dependency warnings. The current build passes the 31-source Chromium save/attachment-readback flow and two HTML safety checks. Jike feed images use the real CDN; other images remain controlled PNGs. API/backup ID comparison confirms that all original 17 notes and one token remain, with no additional notes. Correctness, design and simplification reviews have no unhandled substantive findings.

These repairs remain local in the contribution worktree, without a commit, push or PR. The user controls the ego-lite acceptance space, so its installed extension was not reloaded this round. The current login-truncated BOSS page, native Edge/Firefox saving and other authenticated layouts still need live acceptance; older records below describe their respective revisions only.

2026-10-15 Upstream synchronization and remaining gaps

The existing contribution worktree and branch now use upstream baseline 7b03c8db, retaining the clipper changes and adapting them to the current React popup. Login/content-restriction badges and guidance remain visible; saving, error and success feedback take priority, while explicit selections remain allowed. The removed legacy popup stylesheet is not restored.

A context-menu capture on a truncated Xueqiu feed card renders only its own public detail in a temporary same-origin frame, retaining the existing page session and browser-computed CSS visibility. The frame uses sandbox="allow-same-origin" without scripts and is removed after success, failure or timeout. Wrong identities, CSS-hidden bodies, recycled cards, navigation and inaccessible content create no note. The pointer listener still performs no network requests. Live Ego verification covers a current selected card, public detail reading and cleanup; real-source fixtures separately cover full long text and images.

LinkedIn personal professional headlines are read separately from author names and publication times, and saved as “Author: Name · Professional headline”. The activity, ugcPost and share namespaces remain distinct. Connection degrees, follower counts and nested-post metadata cannot supply the author, headline or time. The real personal sample is Mohammad Ahmed / Technical Lead - Backend at Dizzaract.

Post-sync local macOS non-E2E checks pass: 3,490 bulk tests, 17 API integration tests and 13 desktop authentication integration tests, including 412 extension tests. Root/mobile typechecking, Web and Chromium/Firefox extension builds pass. Firefox lint reports 0 errors, 0 notices and 7 warnings: four from the new upstream React DOM bundles, two existing Readability warnings and one mdast internal-parser warning; checks remain enabled. Rebuilding stale ProseMirror installation links resolves the type conflict without changing dependency versions or business types.

The current 31-source Chromium saving flow passes, covering body/metadata, attachment rewriting and readback, reopening the editor after source blocking, CSS-hidden detail refusal, temporary-frame script isolation/cleanup, and React login/paid-preview guidance. Two additional HTML-safety checks pass. The Jike feed case uses its real CDN and verifies the attachment hash, browser decoding and reopening a cached note offline; the remaining images use controlled PNGs, not renewed live-CDN acceptance. Tests now verify the required rows in the upstream virtualized list instead of counting all DOM rows.

The first run stopped at a Vite session-forwarding timeout; a later Wrangler log records a ProxyController error and process exit. The complete flow ultimately passes through the same workerd’s internal Web/API address. No development-server changes, retries or larger timeouts were added, and the proxy defect is not claimed as permanently fixed. Interrupted-run data is cleaned up. API IDs match all 17 original backup notes with zero additional notes, and the token count returns to the original one. The local extension is reloaded and the same eight-page ego-lite acceptance space is retained. No commit, push, PR or publication was performed.

The current live BOSS page still has a login-truncated body and no readable salary, so full-content acceptance is not established. Native Edge/Firefox saving and other signed-in layouts remain unverified. Earlier records below apply only to their corresponding revisions.

2026-10-15 Cross-platform defect review

The earlier acceptance defects were checked across P1, P2 and the other requested readers. This pass fixes single-newline loss in Douban music reviews, invisible V2EX text/metadata and visible descendants of hidden supplement containers, nested-post body attribution in Facebook/Bluesky/LinkedIn, and hidden header links changing the context-menu target. Medium, Substack, generic pages and explicit selections now share the HTML-to-Markdown converter without compressing blank lines inside code.

Shared table conversion preserves rows, columns, images and cell line breaks rather than displaying an HTML fallback as source text. Only attribute-free <br> tokens inside table cells become hard breaks; arbitrary HTML remains literal. Rich cell blocks become readable inline content, not nested list/quote/code-block nodes. Vertical spans repeat their value within their original row group; horizontal spans use empty placeholders. Additional header rows remain data rows. Image rewriting now uses parser source positions and label boundaries, preserving escaped examples, code, references, nested labels and table images. Generic/selection entry points also report partial image archival.

An isolated experiment with the installed Wrangler proxy reproduces 7 failures in 50 edit/save pairs when the upstream leaves {} unread. Reading the body, applying Wrangler's drain middleware, or sending no body each produces 0/50 failures. The extension removes its unnecessary edit-session request body; API and other clients remain unchanged, and this is not a claim that every Wrangler connection fault is fixed. Substack's actual article and Note now archive 3/3 and 1/1 images through the configured http://127.0.0.1:8787 endpoint. All four attachments decode and match source SHA-256 hashes; both temporary notes and all four attachments are deleted, preserving the 17 existing notes.

All 387 extension tests and 346 shared/editor tests pass, as do root/mobile typechecks, the Web build and Chromium/Firefox extension builds. Firefox lint has 0 errors, 0 notices and 3 warnings: the two existing Readability warnings and a false positive for mdast's internal parser document().write() method, which does not access a browser document. The background bundle is also exercised without a DOM. Independent correctness, design and simplification reviews have no remaining actionable findings in this scope. The dependency patch is verified with a clean isolated install.

The same eight-page ego-lite acceptance space is retained. Native toolbar/context-menu clicks, authenticated layouts without samples and complete cross-browser acceptance remain pending. Existing notes are not rewritten automatically. No commit, push or publication is performed.

2026-10-15 P1 actual-image verification

All five P1 platforms continue through page-images. The actual Bluesky full-size image is downloadable, but extension and source-page fetches fail CORS with the browser reporting MissingAllowOriginHeader. This pass adds only https://cdn.bsky.app/* host access, verified natively after reloading the local extension. No unnecessary CDN permissions are added for the other four platforms.

Current ego-lite pages supply the extracted text and images. The extension page downloads actual CDN bytes; the shared archival function uploads and rewrites temporary notes through the original configured http://127.0.0.1:8787 endpoint. Browser readback verifies Facebook 1/1, Instagram 3/3, LinkedIn 8/8, Threads 4/4 and Bluesky 1/1. All 17 attachments return HTTP 200, match the source SHA-256 hashes and decode successfully, with zero external images in these temporary notes. Facebook uses the current post header's permalink; identity matching is not relaxed to guess old-link aliases.

Instagram's first attempt archives 2/3 despite downloading all three images. A separate check supplies the missing attachment to that same temporary note, so the final result does not establish complete archival in one save. An additional Medium sample passes download, archival and readback for two actual images. Substack's article and Note download and upload all 3+1 images, but each final rewrite encounters a local proxy 503 and cannot be marked archived. The fault recurs after restart. Its symptoms agree with the upstream Wrangler proxy connection-race report, but this pass does not prove the precise underlying trigger, change Wrangler, add product retries or claim a permanent fix.

All 370 extension tests and Chromium/Firefox builds pass; Firefox lint retains the two existing Readability warnings. Native toolbar/context-menu clicks and complete cross-browser acceptance remain manual; source-page permissions are not granted by script in place of the user. Temporary notes and attachments are removed after verification, preserving existing notes. The local extension is reloaded and P1 pages are available in the same acceptance space. No commit, push or publication is performed.

2026-10-15 Image downloads and attachment rewriting

Existing acceptance notes retain 16 external images in the latest WeChat sample, all external images in the Xueqiu and Jike samples, and mixed results for Sspai. WeChat's CDN lacks extension host access and rejects in-page CORS reads. Sspai's CDN returns 403 without a referrer and valid images with the Sspai root referrer. The extension adds https://mmbiz.qpic.cn/* and https://cdnfile.sspai.com/* host access and shares the existing Douban header-rule module with Sspai. Each rule affects only this extension's own HTTPS GETs to the corresponding CDN, without source article paths or queries. Downloads, uploads, edit-conflict protection and URL rewriting continue through page-images.

This pass also reproduces a local Wrangler proxy 503 on the final /save: all 21 images upload, but the note retains all 21 external URLs. After restarting the current local development services, the original configured http://127.0.0.1:8787 endpoint completes actual CDN downloads, temporary-note uploads and rewriting for WeChat 21/21, Xueqiu 3/3, Jike 1/1, Sspai 9/9, Douban 6/6, Juejin 2/2 and the Xiaoyuzhou cover 1/1. All 43 attachments read back with HTTP 200, match their downloaded SHA-256 hashes and decode successfully in the browser; the temporary notes retain zero external images. This verifies recovery of that endpoint's archival flow after restart, without changing Wrangler or claiming a permanent fix for the proxy's underlying fault.

All 370 extension tests, root typechecking and Chromium/Firefox builds pass. Firefox lint retains only the two existing Readability warnings. Toolbar/context-menu bundle regressions cover the Sspai source-header rule; ego-lite verifies native host access, request rules, shared archival and attachment readback. Native toolbar/context-menu clicks remain for manual acceptance. Temporary notes and attachments are removed after verification; existing notes are not rewritten automatically. The local extension is reloaded; clip again to apply the fix. No commit or publication is performed.

2026-10-15 Douban review paragraphs and images

Douban reviews use white-space: pre-wrap, making blank lines within one HTML paragraph meaningful paragraph boundaries. The reader now restores them on a detached copy, retaining emphasis and links across boundaries without splitting code's own blank lines. The sample review retains all seven displayed paragraphs instead of two merged paragraphs, preserving its six image positions.

The previous acceptance note contains six external images and no archived attachments. The CDN returns 418 without a Douban referrer, while in-page fetch is restricted by CORS. The extension adds https://*.doubanio.com/* host access and declarativeNetRequestWithHostAccess. A session rule matches only this extension's own HTTPS GETs for img[0-9].doubanio.com/view/ images and sets the Douban root referrer, without the source page path or query. Images retain the existing page-images byte/time limits, upload and URL rewriting path, with partial-archival feedback on failure. Upgrades may require confirmation of the added site permission.

After reloading the local extension in ego-lite, the native request rule enables 200 responses for all six actual CDN WebP files. The shared page-images flow archives and rewrites all six images in a temporary note. Readback through the configured instance retains seven body paragraphs and zero external images; each attachment's SHA-256 matches its source and all six decode in the browser as valid 1080-pixel-wide images. That pass's complete upload/save verification uses the same API worker's internal address: the regular local Wrangler proxy returned 503 / Your worker restarted mid-request during one upload and a subsequent save. Extension settings and development services were unchanged at that time; the later verification through the original endpoint is recorded above. Native toolbar/context-menu clicks remain for manual acceptance. This live check separately covers real DOM extraction, extension CDN requests, the shared archival flow and API/browser readback.

All 368 extension tests, root typechecking and Chromium/Firefox builds pass. Firefox lint has no errors/notices and two existing Readability warnings. E2E adds paragraph-boundary assertions and passes test collection; the complete E2E is not rerun. Both temporary notes are cleaned up, preserving existing notes. Existing notes are not rewritten.

2026-10-15 Juejin table structure

Manual acceptance found that Juejin's three-column summary table became continuous text. Both the live page and fixture retain the complete HTML table; the shared converter lacked table rules. Capture now uses Joplin's Turndown table plugin to produce GFM tables, retaining headers, rows, columns, links and inline code. Only table rules are enabled. Captions are converted as normal rich-text paragraphs so literal HTML cannot become markup. A pinned dependency patch preserves repeated || characters that the plugin otherwise collapses.

On the same live Juejin page in ego-lite, the note editor's Markdown parser produces one three-column table with one header and four body rows. Every cell and the “事件循环” link match the source; two images, original publication time and source DOM stay unchanged. All 363 extension tests, root/mobile typechecks, Web and Chromium/Firefox extension builds, and diff checks pass. Frozen-lockfile installation passes; existing dependency versions are retained, adding only the table dependency and patch. Actual toolbar/context-menu bundle regressions verify tables before and after image URL rewriting. E2E adds editor row/column assertions; this pass verifies collection only, without rerunning the complete browser persistence suite. Complex merged cells, nested tables and multiline rich content inside cells are outside this acceptance pass. Reload the local extension and clip again; existing notes are not rewritten.

2026-10-15 Sspai article updates

Manual acceptance found that Sspai places article updates in a separate block beside the main body, which the reader previously omitted. Capture now appends the same article's visible updates in page order. Each update becomes a separate blockquote containing its displayed time, bold title and complete body in source order; update titles are not promoted to section headings. Rich content uses the existing conversion and image archival path. It excludes duplicate update navigation, interactions and sidebars. Missing optional titles/times do not discard readable update text; hidden updates remain excluded and original publication metadata stays separate.

Reading the same live page in ego-lite and parsing its Markdown confirms that the time, bold title “中国大陆推出睡眠呼吸暂停迹象提示功能” and complete explanation share one blockquote with no extra heading elements. The original 2024-10-10 publication date, nine images and source DOM remain unchanged. After the quote-format fix, all 123 related extraction/save tests, root typechecking, Chromium/Firefox builds and diff checks pass. Actual toolbar/context-menu bundle regressions cover update text and image URL rewriting. Browser E2E adds persisted-blockquote assertions; this pass verifies collection only, without rerunning the complete E2E. Reload the local extension and clip again; existing notes are not rewritten.

2026-10-15 WeChat body heading hierarchy

The original article title is preserved; only body sections encoded as ordinary paragraphs and typography are repaired. Clearly larger paragraph text is compared with the article's dominant body font size and mapped to heading levels starting at H2. Groups of “第几步:…” step labels sit one level below their section. Existing heading tags, ordinary bold prose, drop caps, numbered actions, quotes, code and captions retain their semantics; heading wording is not rewritten. Bold alone is insufficient when typography provides no heading evidence.

Reading the same live WeChat page in ego-lite confirms three H2 sections and four H3 steps, with the original title, 21 useful images and source DOM unchanged. The fixture now retains the necessary computed font size, weight and alignment to reproduce the visual headings. All 355 extension tests, root typechecking, Chromium/Firefox builds and diff checks passed. Toolbar/menu bundle regressions check heading markers both before and after image URL rewriting. Browser E2E gains heading-element assertions; only test collection was checked in this pass, and the full suite was not run. Reload the rebuilt local extension before clipping again; existing notes are not rewritten.

2026-10-15 WeChat manual-acceptance repair

Manual acceptance found that the dedicated WeChat reader retained metadata and the wechat tag but still treated publisher banners and decorative images inside #js_content as article content. The WeChat path now removes explicit blue-text follow/about prompts and their grouped artwork, decorative GIFs labeled as dividers, native CPS ads, and trailing standalone native article recommendation cards. Tutorial actions, code/quoted wording, meaningful GIFs, and inline references remain; individual words such as “click” or “follow” never trigger paragraph removal. WeChat's sibling-per-line <code> widget is normalized into a complete code block instead of retaining only its first line.

This sample now retains its cover and 20 body images, 21 in total. The six removed images are banner artwork, four dividers, and a recommendation thumbnail; the original fixture remains unchanged. Real-bundle toolbar/menu regressions check content and image archival, and reading the same live WeChat page in ego-lite confirms the cleanup and all six model-code lines without modifying its DOM. All 352 extension tests, root typechecking, Chromium/Firefox builds and diff checks passed. Existing notes are not rewritten; reload the rebuilt extension before clipping again. This does not establish live acceptance for every WeChat layout, CDN archival, or the complete save UI.

2026-10-15 follow-up review loop

This pass closes six boundaries: selection-menu saves stop when navigation occurs while queued, extracting, or looking up a notebook, while iframe selections keep their own source URL; Substack Notes filter CSS-hidden content before matching their own cards, so a hidden duplicate cannot hide a readable card; Substack gates use actually visible text, including descendants that restore visibility; Jike preserves confirmed originals when image containers or images themselves have button semantics; Medium still recognizes an article shell without a title and refuses failed extraction instead of falling back to generic content; development E2E skips Service Worker and offline-cache checks because the development server disables the PWA, while an explicitly configured built instance runs them. Real CDN transfer, digest checks, and image reads after source blocking remain in the default test path.

Removed the duplicate source-string assertion for Web document reset, retaining the actual DOM reuse, image release, and undo-history regression. All 348 extension tests and seven Web editor tests passed, along with root typechecking and Chromium/Firefox extension builds; E2E test collection passed. Browser E2E and live-site acceptance were not repeated in this pass; browser results below remain evidence from the previous run. Changes remain in the existing contribution worktree, without a commit, push, or release.

2026-10-15 guideline completion and P1 fixes

Jike H5 topic feeds reuse social-target, capture-platform and the existing save queue to capture only the uniquely identified card under the pointer. Medium/Substack articles now retain available authors, original publication time, web-clip and medium/substack tags. Public metadata must identify the current article; missing metadata never blocks readable text. Images use page-images and return archival status; download/upload/rewrite failure keeps one note and reports that some images remain external links. Medium calendar dates retain date precision, and relative values remain as displayed.

The actual Substack paid-preview .paywall shows an amber “Content restricted” badge and reading-access guidance. Whole-article capture fails, including when the title/body is missing, without generic fallback. Explicit visible selections remain allowed. Paid-article metadata alone does not reject an accessible full article. New messages are synchronized across zh_CN/en/ja/pl.

All five P1 readers filter CSS-hidden content. Missing body text is not restored solely from SEO data. Declared images verify available media; incorrect or missing images cannot be reported as complete. Facebook/LinkedIn literal HTML is escaped at the Markdown text boundary, preserving code blocks. Meta author and publication metadata remain optional. LinkedIn retains its previously supported public JSON-LD full-image/guest-text path; removing irrelevant hidden controls does not reject complete text.

Real-CDN JPEG acceptance exposed a Web editor defect: document reset cleared image nodes that ProseMirror reused. Reset now releases only old media removed from the editor after updating, preserving undo-history isolation. A real ProseMirror regression verifies reused nodes, released old images and zero undo depth after switching. Notebook/list/detail/prefetch repository queries use offlineFirst, allowing the initial IndexedDB or desktop-local read while offline; failed retries still wait for connectivity. Cache formats, authentication, resource storage and migrations are unchanged.

Offline boundaries: Web requires an already authenticated page, synchronized notes and requested attachments cached by the Service Worker. Ordinary Web refresh/new-tab cold startup remains blocked by its existing session request when offline. Desktop/iOS require local notes and previously read attachments; native clients are not accepted in this batch. Android's existing in-memory image cache does not establish cold-start offline access; USB-device verification remains pending.

Validation: 3,117 unit tests and 17 integration tests passed, along with root/mobile typechecks, Web and Chromium/Firefox extension builds, and diff checks. Firefox lint reports 0 errors, 0 notices and the two existing Readability warnings. Persistence for 29 readable samples, the real Substack restriction badge/refusal, and both HTML-safety checks passed as 3 Chromium E2E tests in 59.9 seconds.

The new Jike topic sample uses an actual CDN JPEG; the instance resource matches the CDN content digest. After verifying production Web Service Worker control, attachment caching and the IndexedDB note, clipper.localhost is disconnected to verify failed network requests, reopening the cached note with its text/image, and a new offline search query. Tests do not seed the caches. Other samples still use controlled image downloads; this does not establish all-CDN, signed-in Jike Web or other-browser live acceptance. Native page-player preloads are counted separately from clipper fetches; the clipper is still checked for no audio/video download.

Verification connects directly to the owned worker's internal origin, avoiding reproduced Wrangler proxy 503 responses and stale asset manifests. A temporary E2E configuration creates and validates a dedicated session through the existing local-dev CLI; product authentication is unchanged. API readback confirms test notes/tokens are cleaned up and pre-existing notes preserved. The test session is revoked, the owned worker and browser task space are closed, and the original development server remains running. Changes are uncommitted, unpushed and unpublished.

Remaining requested platforms (2026-10-14)

The same existing contribution workspace now also implements WeChat Official Accounts, Jike, Sspai, Juejin and Douban. These changes are local and are not committed, pushed or published. No new instance API, dependency, permission or data migration is added. Toolbar details and dedicated context menus use the same readers; explicit selections retain priority.

Platform Saved content Verified boundaries
WeChat Official Accounts Article title, full rich-text body converted to Markdown, account name, available author/time, declared cover and lazy-loaded body images. Supports short /s/{id} and identity-bearing /s?__biz=…&mid=…&idx=… URLs; sn is preserved when present. Share/reward/footer controls are excluded. A missing author, cover or date does not reject readable title/body.
Jike Complete visible post text and links, author, available time, ordered public original pictures and link-preview cover. Public mobile share details were sampled for one image, nine images and long text, plus an H5 topic feed. Topic context menus uniquely bind own author profile, text and pictures to loaded public post data; array position and body references never supply the ID. The toolbar still requires a selection or a post detail. Loaded public post data verifies identity/completeness and resolves originals; hidden text is not imported. A local expand control has a bounded wait. Web detail redirects to the QR login page show the amber login badge and refuse whole-page capture. Signed-in Web layouts remain unverified.
Sspai Article title, full structured body, update titles/displayed times/bodies, author, original publication date, original images and captions. /post/{id} details; retain updates in page order and exclude duplicate update navigation, hidden author popovers and interaction/sidebar UI.
Juejin Article title, complete body, public author/time metadata, images, structured comparison tables and fenced code with language and indentation. /post/{id} details; remove copy-code controls. Empty image placeholders are not archived images.
Douban Book/movie/music long reviews, diaries and one selected short comment, with available author/date/rating and body images. Long reviews and diaries use exact content roots. On subject comment lists, right-click the intended card or select a passage; the toolbar does not save the whole list. Preserve the working list source URL and its existing comment anchor because sampled direct short-comment links returned 404. Dates marked edited are not reported as original publication dates.

Unreadable supported details fail explicitly. Known stale identities, truncated text, missing or incorrect declared Jike pictures and hidden content are not saved as complete posts. Optional metadata remains optional. Login pages and comment lists allow only the user's initial explicit selection; if it disappears, capture uses the recorded original text without saving the whole page. Existing image transfer limits and partial-success feedback remain unchanged.

Real browser DOM context-menu events also verify exact short-comment pointer targeting for book, movie and music lists. Eleven sanitized real-page fixtures record source URLs and expected content in apps/extension/fixtures/platforms/sources.json. Browser reader checks cover the public pages; local expansion success/timeout/navigation are tested using the actual bundle with controlled DOM states, not a live Jike expand click. Chromium persistence tests replace source images with controlled downloads, so they do not establish real-CDN transfer, Edge or Firefox runtime acceptance.

2026-10-14 verification: 3,071 unit tests and 17 integration tests passed, along with root/mobile typechecks, the Web build, Chromium/Firefox extension builds and git diff --check. Firefox lint reports 0 errors, 0 notices and the two existing upstream Readability warnings. Independent correctness and design review closed the discovered missing/stale Jike content, incorrect picture binding, hidden metadata and disappearing-selection fallback defects.

The 28-sample Chromium persistence test passed in 52.7 seconds, covering the ten new detail fixtures and all eighteen prior samples. Each saves through the actual built extension and local API, checks stored body and expected image references, reopens the Web editor after blocking sources, verifies all article images, and rejects unreadable variants without a second note. Two separate HTML-safety checks also passed. The editor's source-less ProseMirror separator images and its own code-copy controls are excluded from article-content assertions; archived text and every expected attachment remain checked.

The local development request-forwarding layer twice reset connections at unrelated editor metadata requests. The test now uses the same workerd origin for the built Web, API and extension when EDGE_EVER_CLIPPER_TEST_INSTANCE_URL is supplied. Without that variable it uses the normal configured base URL. The owned local server was restarted after the Web build to refresh its asset manifest; no product API changes, retries or larger timeouts were added. API readback confirmed zero test clips and zero test tokens after cleanup. The browser task space was closed. No commit, push, PR or publication was performed; the installed main-workspace extension was not replaced. To preview these adapters, load edgeever-clipper-p2/apps/extension/dist and refresh the source page.

2026-10-14 additional review: fixed concurrent toolbar and context-menu captures exchanging selected text, and navigation during restricted selection capture/save. Toolbar saving now joins the existing clip queue once; the clicked tab and source URL are fixed before waiting. The queued job, captured response and post-notebook save each verify the original URL where generic/selection capture is used. Inner platform/video queue calls were removed to avoid nested waiting. This also covers a concurrent generic toolbar capture; no new queue, retry, API or metadata prerequisite was introduced. Seven actual-bundle regressions cover the two concurrent entry combinations, active-tab switching while queued, Jike/Douban navigation during injection or notebook lookup, and a timed-out capture replying after the next queued capture starts. Generic page/selection messages now carry a request ID; only the matching pending request consumes a reply, and timeout/injection cleanup cannot clear a later request.

Additional-review validation: 3,078 unit tests and 17 integration tests passed. Root/mobile typechecks, Web/Chromium/Firefox builds and diff checks passed; Firefox lint retains 0 errors and two existing Readability warnings. The complete 28-sample Chromium persistence test and both HTML-safety tests passed together in 52.3 seconds. Independent follow-up review confirmed the concurrency, navigation and late-response findings are closed, with no new substantive finding. API readback confirmed zero test clips/tokens; the owned local server was stopped. Changes remain uncommitted, unpushed and unpublished. Authenticated Jike Web layouts, real-CDN transfer and other browser runtime acceptance remain outside the verified scope.

Phase 2: BOSS Zhipin, Xueqiu and Xiaoyuzhou (2026-10-12)

The baseline is official 3855efb3; P1 merged through PR #521. P2 is implemented in contribution workspace edgeever-clipper-p2, branch feat/clipper-phase2, preserving unrelated work in the original workspace.

Platform Current behavior Explicit limits
BOSS Zhipin Save the job title, readable salary, city, experience/education, visible benefits, complete responsibilities and requirements, company introduction and work address. Only zhipin.com/job_detail/{id}.html; validate canonical identity when present. Require a readable job title and body, and refuse explicit login truncation. Salary, experience/education, company and address are retained when available and omitted when absent/hidden; do not require a salary format, retrieve protected data or treat the page update date as publication time.
Xueqiu Save public detail text, author, original post publication time and body images; add web-clip, xueqiu, 投资 and codes explicitly linked from the final sanitized body. Preserve leading zeros in five-digit Hong Kong codes. Limit stock tags to 21 plus 3 fixed tags, matching the instance's 24-tag limit; retain every stock link in the body. Do not infer stocks from plain mentions, comments or sidebars; modification time is not publication time.
Xiaoyuzhou Reuse complete Show Notes/current-route validation, preserving timestamps, podcast name, cover and explicit episode host text. Do not infer episode hosts from podcast authors, download audio, transcribe it or invent timestamp links. Keep timestamp nodes without href as source text. Add CSS-hidden subtree/title protection.

The toolbar, dedicated context menus and current-page indicator recognize BOSS jobs and Xueqiu details. The indicator describes capture mode; saving still checks readability. Xueqiu detail reads bind to the current page URL; author and publication time are optional, while explicit conflicts in available own permalinks/profile identity still reject. Home/profile pointer targets require the card's own permalink; duplicate occurrences of the same URL do not imply multiple posts. Sampled cards are truncated previews. A context-menu capture renders only the selected card’s public detail in a temporary, script-disabled same-origin frame, preserving browser-computed CSS visibility. Login/challenge pages, inaccessible frames, incorrect identities and navigation fail; neither previews nor the whole feed are saved as complete posts.

The user-provided BOSS job 0d7e760b0a0e7c3a0nF939S0E1NU initially showed login-truncated requirements and SVG salary placeholders; after reload its full 25-50K·13薪 salary, requirements, company introduction and address were readable. Both states have sanitized fixtures. The readable BOSS fixture marks nodes hidden by computed browser CSS as hidden before removing styles, testing that randomly hidden interference text never reaches the note. The public Xueqiu article retains three images and three explicit stock codes. A new “下课以后” episode verifies six timeline nodes and explicitly named hosts 阿丁 and 毛毛.

Validation covers sanitized real DOM, identity/visibility/access boundaries, toolbar/menu parity through the actual bundled background and readers, persisted stock tags and image archival. Chromium integration uses a fresh local Web/API from this workspace and 18 page samples, including the new job, Xueqiu article and explicit-host episode; it checks attachments and reopened editor content after source blocking, refusal without note creation, and cleanup of test notes/tokens. Original image responses are replaced with test PNGs, so fixture E2E is not live CDN-download acceptance. Edge/Firefox live saving, Firefox Android, other BOSS layouts/mobile pages and all authenticated feeds remain unverified; no extension-store version is published.

P2 baseline validation: 3,020 unit tests and 17 integration tests pass; root/mobile typechecking, Web and Chromium/Firefox extension builds pass. Firefox lint has 0 errors and 2 existing dependency warnings. The 18-sample Chromium saving flow and inert-HTML test both pass. P2 code is not yet committed, pushed or submitted as a PR.

2026-10-12 addition: opening the extension runs a read-only DOM probe on BOSS jobs. Only the visible “登录查看完整内容” marker inside the current job body triggers an amber “Sign in needed” badge and sign-in/refresh guidance; hidden leftovers and unrelated login controls do not. Permission failure or navigation during probing shows “Unknown” without the green adapted check. This badge does not establish completeness of other fields; saving still validates identity and full content. The button stays enabled for valid text selections, while a restricted job without a selection still refuses note creation. The hint never overwrites capture feedback already in progress.

Login-badge validation: 248 extension tests and root typechecking pass. The 18-sample Chromium saving flow also verifies the actual readable/login-preview popup states. Chromium/Firefox builds pass; Firefox lint retains 2 existing warnings and no errors.

2026-10-13 review fixes: withdraw unsupported BOSS metadata/salary-format prerequisites, Xueqiu detail author/time-link prerequisites and generic expand-class refusal. Stock tags and Markdown consume the same sanitized body, excluding stocks linked from controls or scripts. Retain the actual 24-tag instance limit and withdraw the unsupported 15-character stock-code cap. CSS filtering distinguishes subtree hiding from descendant-overridable visibility: remove hidden own text while retaining explicitly visible descendants; BOSS availability and Xiaoyuzhou extraction follow the same boundary. Both BOSS fixtures further remove unused action redirects, tracking and security parameters.

Post-review validation: the serialized full non-E2E run passes 3,031 unit tests and 17 integration tests. Root/mobile typechecking, Web and Chromium/Firefox extension builds pass; Firefox lint has 0 errors and 2 existing dependency warnings. The Chromium computed-visibility and inert-HTML safety tests pass. Several unchanged tests timed out during the initial parallel run; isolated checks and the final full rerun pass without changing those tests or production infrastructure. The 18-sample integration rerun did not complete: the local development API proxy first returned 503/timeouts. With EDGE_EVER_CLIPPER_TEST_INSTANCE_URL reaching the same workerd directly, Xiaoyuzhou and BOSS save and API body readback pass, but editor reopening times out while loading the local Vite page. At a host load of about 38, the final rerun again times out navigating to Web. Test timeouts and production flows were not changed. Earlier 18-sample passing records describe their respective revisions only; this review does not claim a full E2E acceptance pass. Test notes and tokens from this review were cleaned up, with API readback confirming none remained.

Phase 1: five social platforms (2026-10-10)

Facebook, Instagram, LinkedIn, Threads and Bluesky now have dedicated readers. Open a supported post and use the toolbar, or right-click the post card and choose its platform command. Selection capture retains priority. On an already open feed, reload the page so the target listener is installed; if the card cannot be resolved, open its detail page. No automatic capture or login is performed.

Platform Supported detail URLs Saved content
Facebook facebook.com/{account}/posts/{id}, permalink.php and story.php Full readable main post, author/organization, available time and loaded photos; excludes comments and controls.
Instagram instagram.com/p/{code}/, /reel/{code}/ Complete readable caption, handle, time and all loaded carousel photos or video covers.
LinkedIn linkedin.com/posts/…-{type}-{id}-…, /feed/update/urn:li:{type}:{id}/ Full post, publisher, personal professional headline, time and complete loaded image collection (type: activity, ugcPost, share).
Threads threads.com/@{handle}/post/{code} and threads.net aliases Full post, handle, time, loaded images and explicit quoted content.
Bluesky bsky.app/profile/{handle}/post/{id} Body, author, available time, full-size CDN images and visible quoted post.

Tags are web-clip and facebook, instagram, linkedin, threads or bluesky. Videos are not downloaded. Missing carousel items, truncated text, login walls and incorrect IDs cause an explicit failure. Source identity uses the card header, excluding links inside body text and quoted posts. Hidden Meta cards cannot establish readability.

Signed-out real pages were sampled in Ego Chromium; all five pointer targets were verified live, including a Bluesky feed. Sanitized fixtures retain expected image counts 1/3/8/4/1 for Facebook/Instagram/LinkedIn/Threads/Bluesky. Actual bundled script tests cover toolbar/menu parity, feed selection, quoted content, queued right-clicks, navigation, incorrect identity and partial images. The Chromium persistence test loads the real extension against these fixtures and saves through the local API; its image endpoint is a controlled local server, not the live CDN. It verifies every expected attachment and reopened editor content after blocking the sources.

The PR includes this implementation and its regression checks. 210 extension tests, root/mobile typechecking, Web and Chromium/Firefox builds pass. Firefox lint retains two upstream Readability warnings. Authenticated feeds, Edge/Firefox runtime saves and Firefox Android remain unverified.

The eight-platform Chromium E2E passes (three earlier adapters plus Phase 1), including all expected image resources and reopened editor images, unreadable-page refusal and cleanup. Wrangler 4.112.0’s development proxy intermittently returns 503 on POST with “Your worker restarted mid-request.” This run used EDGE_EVER_CLIPPER_TEST_INSTANCE_URL=http://127.0.0.1:64641 to reach the same local workerd API directly; that internal port must be resolved again for a new dev process. The default instance URL remains the test base URL. No production API or runtime code was changed. The installed Ego development extension was reloaded; existing source tabs need refreshing for the new target listener.

2026-10-11: Fixed Instagram carousels with individual slide captions being rejected as unreadable. The reader establishes readable content using the target permalink and the visible slide caption, while retaining every loaded slide caption and media cover, replacing a truncated parent prefix with complete slide text and preserving independent parent text. The live Google post DeKe6teEpya yielded the loaded parent caption and 20 covers (one video, 19 photos); regression checks cover different visible slides, hidden cards, unrelated text and missing carousel items. Videos themselves are not downloaded. The added sample passes Chromium E2E through the actual extension and local API, including all 20 archived images and reopening the note with source hosts blocked; this run used the default local instance URL.

2026-10-11: Added LinkedIn ugcPost share URLs and signed-in SDUI cards, retaining distinct UGC and activity identities. The main commentary supplies the exact UGC ID; comments and referenced links cannot supply it. The live sample 7497764716677758977 yields the complete text, Friends of NASA, the displayed relative publication time and eight images. LinkedIn safety redirects in archived text are unwrapped to their destinations without redirect tracking parameters. The targeted Chromium E2E passes through the actual extension, local API, eight image uploads and reopening the note with source hosts blocked, using the same workerd internal API address to bypass intermittent development proxy 503s. The full-suite attempt hit a proxy 503; its rerun stalled in the earlier Instagram browser flow and was interrupted, so this run does not claim a full-suite E2E pass. Test notes and tokens were cleaned up.

2026-10-11: Added signed-out LinkedIn UGC posts. Public cards declare both data-activity-urn and data-attributed-urn, while JSON-LD uses the activity URL. The reader matches the requested UGC identity through the card-root declaration and retains the requested source identity. Anonymous HTTP responses contain the full body, exact publication time and eight images; login is not required. Incorrect attribution IDs and links inside commentary remain rejected. The signed-out sample passes a targeted Chromium E2E through the actual extension and local API, including eight archived images displayed after reopening with source hosts blocked. The consecutive multi-state test did not finish, so this does not claim a full-suite E2E pass.

2026-10-11: Compared signed-in and signed-out clips of the same LinkedIn post in the local instance: body text, eight images and their order match. Removed author profile metadata (such as follower counts) accidentally prepended to the post; the same words within actual commentary remain intact. Signed-in and signed-out bodies share cleaning and Markdown conversion: normalize line breaks, redirects, hashtag links and bold styling added by LinkedIn to link labels. JSON-LD supplies full text only when visible commentary is incomplete. Both real-page samples produce identical body Markdown and link destinations in Chromium, retaining eight images each; the regression test directly compares both bodies. Publication times retain the exact or relative values supplied by each page. Existing notes are not rewritten automatically.

2026-10-11: Fixed readable caption matching for Threads DeMqtuYgkaL, whose visible link label is shortened. Compare the caption link against the actual href only within the exact post card and timestamp-permalink boundary; wrong targets remain rejected. The live reader yields the full caption, NASA, original publication time and one video cover. The video is not downloaded.

Substack Notes and rendered articles

Save Substack Note detail URLs https://substack.com/@{handle}/note/c-{id} from the toolbar or their page context menu. Bind to the original author path, Note ID and header permalink, preferring the complete detail over a truncated recommendation card for the same post. Keep rendered paragraphs, formatting, author, source time and loaded attachments; exclude avatars, reactions, replies and sidebars. Hidden or truncated content fails explicitly. This adapter covers these detail URLs; feed context-menu targeting is not claimed.

Substack newsletter articles use the page-clip entry point. Recognize Substack subdomains and custom domains carrying Substack stylesheet markers. Keep the article title, subtitle, body, sections, images and captions; remove subscription widgets, share buttons and heading-link controls. Selection takes precedence. Only current-page content is read; paid articles and special media embeds remain unverified.

2026-10-11: Tested the user-provided Ted Gioia Note c-357811021, whose signed-out page exposes five complete paragraphs and one attachment; source publication time comes from its JSON-LD. Live extraction excludes replies and sidebars. Also tested the public One Useful Thing article the-dot-and-the-swarm on its custom domain, retaining opening/final paragraphs, three sections and three images. Both sanitized structural samples pass targeted Chromium E2E through the real extension, local API, all image uploads and reopened editor images after source blocking. An additional Note audit downloads its actual Substack CDN image independently (65,583 bytes), verifies identical SHA-256 after archiving, and displays it after reopening with sources blocked. Article attachment testing uses a controlled download source. Test notes and tokens were cleaned up. The full platform E2E suite was not rerun; this does not establish acceptance of every Substack page or all browser runtimes.

Medium rendered articles

Medium continues to use the generic page-clip entry point, with added story-block extraction. Retain the displayed title, subtitle, body, sections, images and captions; exclude member notices, reaction counts, highlighting controls and image-viewer prompts. Recognize Medium hosts and custom domains with Medium site metadata. Do not fetch hidden paid content. Selection still takes precedence.

2026-10-11: Tested the user-provided story a2ce2e6de88e; its Medium URL redirects to scottbatson.dev. The current browser can read the full body. Live extraction retains its opening and final paragraphs, Slow work/Writing sections, two images and captions. This article and the Threads sample above pass a targeted Chromium E2E through the actual extension and local API, including all image uploads and reopening notes with source hosts blocked. Image sources use a controlled local server, so this does not establish live CDN transfer or acceptance of every Medium story. The test uses the same workerd internal address to bypass intermittent development proxy 503s. Test notes and tokens were cleaned up. The full E2E suite was not rerun in this change.

Earlier detail-page adapters

Usage

Configure the extension's EdgeEver instance and API token, open a detail page, and save from the toolbar or its platform command in the page-background context menu.

Platform Detail page Saved content
Hacker News Main posts at https://news.ycombinator.com/item?id=… Title, available author and publication time, points at capture, body and original external link. Link-only posts are valid; linked articles are not fetched.
V2EX https://www.v2ex.com/t/… or https://v2ex.com/t/… Body, available author and publication time, every supplement with its number and available timestamp, excluding replies.
Xiaoyuzhou https://www.xiaoyuzhoufm.com/episode/… Episode title, podcast name, publication time, complete Show Notes, their timeline and explicitly named hosts, cover and body images. Timestamps without working links remain text.

A text selection takes priority in the toolbar. Existing selection and image commands remain; the new commands use only the page context. Home pages, feeds, podcast pages, profiles and HN comment pages are outside these dedicated adapters; open a detail page first.

Platform notes receive web-clip and hacker-news, v2ex or xiaoyuzhou tags. Source URLs omit tracking parameters, reply pagination and anchors. Publication and capture times are separate. Date-only and relative times keep their precision; missing fields are omitted.

Capture, publication and supplement times use the browser system timezone at capture, formatted as yyyy-MM-dd HH:mm:ss without timezone labels or fractional seconds. In an Asia/Shanghai system environment, V2EX’s 2023-12-13T13:25:31+08:00 becomes 2023-12-13 13:25:31. Known instants are converted to the system timezone; unknown zones retain their source wall clock, and date-only or relative values keep their original information. HN timestamps without a zone have been checked against Unix timestamps from its official API, so the HN reader appends Z. These times are saved as body text and do not change with later device timezone changes. Existing video notes record only the local capture date. V2EX supplements use their number as a heading and put the timestamp in a separate plain paragraph. Formatting changes apply to new clips; existing notes remain unchanged.

An unreadable recognized detail page is not saved as a generic whole page. Follow the error to sign in, wait for loading, expand the text, or reopen the intended page before retrying. Xiaoyuzhou metadata is saved with “This episode has no Show Notes” only when confirmed empty; a read failure does not mean empty content. Audio is not downloaded or transcribed, and no summary is generated.

Images and feedback

The body is saved first, followed by the existing image-copy workflow: up to 30 images, 20 MiB per image, 60 MiB combined, and a 45-second overall budget.

  • Notes without images or with every image copied report success. Images are described as archived only after every image is copied.
  • Download, upload, rewrite or budget failures preserve the note and report “Text saved. Some images still use external links.” Images beyond the 30-image limit count as uncopied.
  • If the user edits the note during copying, their version is retained. The clip does not overwrite it or create another note.

Image archival means that EdgeEver instance resources can serve the images, not a new promise of complete offline client access.

Verification record

The PR code baseline is upstream 96626ef2; the development extension version is 0.1.17, without a store version bump. Earlier verification records below describe the previous local batch.

Earlier detail-page checks passed:

bun run test:extension
bun run typecheck
bun run typecheck:mobile
bun run build:web
bun run build:extension
bun run build:extension:firefox
bun run lint:extension:firefox
bunx playwright test tests/e2e/web-clipper-html-safety.spec.ts tests/e2e/web-clipper-platforms.spec.ts tests/e2e/web-clipper-page-images.spec.ts --reporter=line

136 extension tests and 3 Chromium E2E tests pass, along with root/mobile typechecking, the Web build and Chromium/Firefox extension builds. Firefox lint reports 0 errors, 0 notices and 2 warnings. Lint and Chromium results do not establish Firefox runtime acceptance.

2026-10-09 follow-up: HN commit 16e11216 saved publication times without a timezone. The sample's 1715879518 from the official API corresponds to 2024-05-16T17:11:58Z. The HN reader now retains that UTC marker, with explicit zones, date-only values and relative times verified unchanged. Three cross-world extension resource mismatch warnings reproduced in the installed Ego Chromium extension's settings page were eliminated by scoping modulePreload: false to the extension build. Settings and popup pages load normally, and Test connection successfully returns notebooks.

The Xiaoyuzhou UNSAFE_VAR_ASSIGNMENT warning is fixed by reusing the existing Domino dependency to parse completeness data in a JavaScript-only DOM. It still saves only content from the page DOM. The injected script grows by about 236 KB, without new dependencies or permissions.

2026-10-10: the Readability patch added solely to remove third-party warnings, its registrations and dedicated tests were removed. The locked, unmodified @mozilla/readability@0.6.0 dependency was reinstalled. Its two static warnings for article retries and <noscript> image parsing remain visible; no lint rules are suppressed. The caller only passes a detached document copy with scripts, embeds and <noscript> already removed. Readability does not sanitize untrusted HTML, and its output must not be inserted directly into a page as safe HTML.

After removing the patch, 135 extension tests and 3 Chromium E2E tests passed again. The Show Notes test disallows browser HTML assignment and parsing, then verifies that script, event, image, iframe, audio and video probes cause no code execution or resource requests. A control image in the live page successfully triggers a request and event. The other two E2E tests cover generic page-image saving and persistence of platform notes and archived images. This runtime evidence covers Chromium.

  • DOM fixtures retain relevant structures from the public pages below, removing unrelated content and sensitive parameters. Sources and expectations are recorded in apps/extension/fixtures/platforms/sources.json. Derived boundary variants are synthetic tests, not live samples.
  • Coverage includes metadata, supplements, code/images, unsafe HTML, time precision, empty content, expansion timeouts, selection priority, message correlation, permissions, navigation, partial images, limits and edit conflicts.
  • Playwright 1.62.1 loads the real extension in Chromium / Chrome for Testing 151.0.7922.34, saves all three samples through the local API, verifies success and unreadable failure paths, and reopens notes in the Web editor. After closing the source page and blocking external sources, the Xiaoyuzhou cover still renders from the instance attachment. Only the temporary test extension receives fixed test-host permissions; the shipping manifest adds none. Test notes and tokens were cleaned up.
  • The existing generic page-image E2E passes. Extension tests also cover selection, image, X, Reddit, Xiaohongshu, Zhihu, GitHub, YouTube and Bilibili code; their live sites were not individually replayed.
  • Independent correctness, simplification and design reviews have no unresolved substantive findings. Fixes cover cleaned-empty selections falling through to whole articles, title-whitespace false mismatches, and stale data after Xiaoyuzhou client navigation.

Live sampling used a signed-out Ego Chromium browser reporting Chrome/152.0.0.0 in its UA. These steps run the built extraction script; persistence is verified separately by the local-instance E2E above.

Sample Expected and observed
HN post 40380738 Successfully retains jnnnthnn, the original time, the full main post through its final paragraph and the external link, excluding comments.
HN comment 40384810 Correctly reports unreadable and refuses it as a main post.
V2EX 1000000 Direct HTTP sampling and fixture tests retain the body and two ordered, dated supplements, excluding replies. Live browser navigation timed out; saving on this live site remains unverified.
Xiaoyuzhou episode 25 Preserves timestamps and the final music credit. Full notes are already loaded before expansion, so no extra click is needed.
Xiaoyuzhou episode 161 After navigating from episode 25 via its podcast page, bootstrap __NEXT_DATA__ still has the old ID. Validating the DOM against the current route's loaded episode data yields the new ID, title and body without old content.

The complete live-site save workflow with the extension loaded in each of Chrome, Edge and Firefox is still pending. Firefox Android is also unverified, so this batch must not be marked fully accepted yet. A 2026-10-09 check confirmed that the initial HN implementation was merged through PR #505. This PR includes the HN time fix, preload fix and V2EX/Xiaoyuzhou implementations.

Local review on 2026-10-11

The review corrected a truncated Instagram parent caption by saving the complete loaded per-slide captions, retaining independent parent text. It also bound Meta readability and context-menu targeting to the same post card, excluded hidden Facebook/Bluesky/LinkedIn bodies, removed an unsupported Bluesky image-count guess based on ordinary fractions, and stopped recognized unreadable Medium/Substack articles from falling back to whole-page extraction. Article identity and Markdown conversion now reuse shared helpers. The previous Instagram checks did not assert the final slide text; the new regression and Chromium editor check do.

The end-to-end fixture suite covers all 15 samples through the real extension, local API, image archiving and reopening with source hosts blocked, plus unreadable/hidden refusal and cleanup. It uses the same workerd directly for extension, API assertions and editor API requests because the local development proxy intermittently times out. This verifies the local business flow, not the proxy or live CDN behavior across every site/browser. The HTML safety browser check also passes. Firefox is build/lint checked only; there is no new Firefox runtime acceptance in this review.