You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On closed-access nature.com / link.springer.com articles that show a "Buy article PDF USD 39.95" paywall CTA, instsci papers judges the page as already logged-in, so it never enters the institutional-login flow. Instead the generic PDF-button clicker matches the Buy button (:has-text('PDF')), clicks it, and the run ends with a nature.com.pdf 404 / pdf_not_captured. This violates AGENTS.md step 5 ("let the user complete institution login; wait + resume"), which never happens because the SSO path is short-circuited upstream.
Reproduce
instsci 0.1.1, Windows, CloakBrowser 0.4.9, Shibboleth/CARSI via university IdP.
Command:
instsci papers dois.txt --publisher auto --institution "<your institution>" --no-broker
dois.txt contains the closed-access DOI 10.1007/s11630-023-1652-y (Journal of Thermal Science, Springer).
Expected: the "Buy article PDF" paywall is detected as a hard auth wall; instsci clicks nature.com's "Access through your institution" link (→ wayf.springernature.com), waits for the user to complete SSO, then downloads the entitled PDF.
Root cause
All references are against instsci/publisher_batch.py unless noted. Verified against the current main.
A. _looks_logged_out returns False for the Buy-PDF paywall
_looks_logged_out (defined line 2684) has a success-article branch whose return preempts the sso_text_markers fallback:
The hard_wall_markers tuple (lines 2703–2719) contains "purchase pdf" (2714) and "purchase this article" (2715), but not"buy article pdf", "buy pdf", "add to cart", or any price/usd/$ pattern. So a Nature page whose body text contains only Buy article PDF USD 39.95 matches nothing in hard_wall_markers → _looks_logged_out returns False → the page is judged logged-in.
Because line 2720 returns inside the if, the sso_text_markers fallback at line 2721 is never consulted for a success-article URL — even though SPRINGER_PROFILE.sso_text_markers (publisher_profiles.py:454–459) does include "access through your institution", which is exactly the link we want.
B. _ensure_login short-circuits on the bad signal
_ensure_login (defined line 678) early-returns when _looks_logged_out is False:
With the paywall misjudged as logged-in, _ensure_login returns True here and never reaches _complete_login_from_current_page (line 687). No SSO entry is ever clicked, and no institutional-login wait is entered.
C. _click_pdf_entry's generic selectors match the Buy button
With the run now believing it is logged in, _click_pdf_entry (defined line 2052) is reached. Springer/Nature is not one of the publisher-specific branches (lines 2053–2061 guard on elsevier/aps/wiley only), so execution falls into the generic catch-all tuple:
The loop (lines 2072–2092) clicks the first visible match with no purchase/buy denylist — unlike the Elsevier path, which penalizes purchase pdf (score -= 80 at line 1034). Playwright :has-text() is a substring match, so a Buy article PDF button satisfies both selectors and gets clicked. The second-stage isPdfControl JS (lines 2094–2142) is never reached because the generic selector already matched first.
Why no path partially fixes this
Repo-wide, the only "purchase" handling is: "purchase pdf"/"purchase this article" in hard_wall_markers (2714–2715); the Elsevier-only score -= 80 (1034); and the Elsevier-only entitlement check _elsevier_lacks_pdf_entitlement (line 2741, gated on profile.name.lower() == "elsevier"). None of these apply to the Springer/Nature path. There are zero occurrences of buy, add to cart, usd, shopping cart, or a price regex anywhere in the repo.
Why this is wrong vs. AGENTS.md
AGENTS.md step 5 instructs the harness to "let the user complete institution login; wait + resume" when a closed-access page requires SSO. That step is only reached via _complete_login_from_current_page, which is only called when _looks_logged_out returns True. Because the Buy-PDF paywall makes _looks_logged_out return False, the SSO wait is skipped entirely and the Buy button is clicked instead — the opposite of the documented flow.
Suggested fix
Non-prescriptive; happy to take either direction.
Recognize the Buy/Cart paywall (root cause A). Either
add "buy article pdf", "buy pdf", "add to cart" (and optionally a price-with-intent pattern like usd\s?\d / \$\d) to hard_wall_markers (lines 2703–2719); or, more robustly,
restructure the success-article branch so the sso_text_markers fallback is also consulted, e.g. return hard_wall_match or any(marker in text for marker in self.profile.sso_text_markers). This also catches future paywall phrasings that overlap with SSO link text.
Never click a Buy/Cart/price button as the PDF entry (root cause C). Add a purchase denylist to _click_pdf_entry's generic loop (lines 2072–2092) — skip any :has-text('PDF') match whose visible text/href contains buy, purchase, add to cart, or a price. The Elsevier path already does the equivalent at line 1034.
Prefer the working SSO link for Springer/Nature._click_sso_entry (line 814) already has generic a:has-text('Access through your institution') selectors (lines 830–838) that route to wayf.springernature.com; consider also guarding against the dead /institutional-login (404) href. This is secondary — _click_sso_entry is unreachable until fix Request for Collaboration Quotation #1 unblocks _ensure_login.
Late-render nuance. The Buy CTA appears after domcontentloaded, so detection may need a short wait / locator poll before _looks_logged_out is evaluated, otherwise the markers may not yet be in the DOM.
tests/test_acs_batch.py — _looks_logged_out exercised only with RSC/Elsevier/ACS/Wiley profiles; no Springer/Nature paywall-detection coverage
Notes for tests
Two existing intentional behaviors worth preserving when fixing this:
test_publisher_article_title_is_not_treated_as_auth_wall (test_acs_batch.py:277) asserts _looks_logged_out is False for an RSC page whose body contains the benign phrase "purchase options". This is likely why "buy article pdf" was never added. A fix should still pass this case — "Buy article PDF USD 39.95" (price + CTA verb) is a distinct, harder signal than the soft "purchase options" wording.
A new test exercising _looks_logged_out with SPRINGER_PROFILE on a nature.com/articles/... page containing "Buy article PDF USD 39.95" would directly cover this gap.
Summary
On closed-access
nature.com/link.springer.comarticles that show a "Buy article PDF USD 39.95" paywall CTA,instsci papersjudges the page as already logged-in, so it never enters the institutional-login flow. Instead the generic PDF-button clicker matches the Buy button (:has-text('PDF')), clicks it, and the run ends with anature.com.pdf404 /pdf_not_captured. This violates AGENTS.md step 5 ("let the user complete institution login; wait + resume"), which never happens because the SSO path is short-circuited upstream.Reproduce
instsci papers dois.txt --publisher auto --institution "<your institution>" --no-brokerdois.txtcontains the closed-access DOI10.1007/s11630-023-1652-y(Journal of Thermal Science, Springer).wayf.springernature.com), waits for the user to complete SSO, then downloads the entitled PDF.Root cause
All references are against
instsci/publisher_batch.pyunless noted. Verified against the currentmain.A.
_looks_logged_outreturns False for the Buy-PDF paywall_looks_logged_out(defined line 2684) has a success-article branch whosereturnpreempts thesso_text_markersfallback:The
hard_wall_markerstuple (lines 2703–2719) contains"purchase pdf"(2714) and"purchase this article"(2715), but not"buy article pdf","buy pdf","add to cart", or any price/usd/$pattern. So a Nature page whose body text contains onlyBuy article PDF USD 39.95matches nothing inhard_wall_markers→_looks_logged_outreturns False → the page is judged logged-in.Because line 2720
returns inside theif, thesso_text_markersfallback at line 2721 is never consulted for a success-article URL — even thoughSPRINGER_PROFILE.sso_text_markers(publisher_profiles.py:454–459) does include"access through your institution", which is exactly the link we want.B.
_ensure_loginshort-circuits on the bad signal_ensure_login(defined line 678) early-returns when_looks_logged_outis False:With the paywall misjudged as logged-in,
_ensure_loginreturns True here and never reaches_complete_login_from_current_page(line 687). No SSO entry is ever clicked, and no institutional-login wait is entered.C.
_click_pdf_entry's generic selectors match the Buy buttonWith the run now believing it is logged in,
_click_pdf_entry(defined line 2052) is reached. Springer/Nature is not one of the publisher-specific branches (lines 2053–2061 guard on elsevier/aps/wiley only), so execution falls into the generic catch-all tuple:The loop (lines 2072–2092) clicks the first visible match with no purchase/buy denylist — unlike the Elsevier path, which penalizes
purchase pdf(score -= 80at line 1034). Playwright:has-text()is a substring match, so aBuy article PDFbutton satisfies both selectors and gets clicked. The second-stageisPdfControlJS (lines 2094–2142) is never reached because the generic selector already matched first.Why no path partially fixes this
Repo-wide, the only "purchase" handling is:
"purchase pdf"/"purchase this article"inhard_wall_markers(2714–2715); the Elsevier-onlyscore -= 80(1034); and the Elsevier-only entitlement check_elsevier_lacks_pdf_entitlement(line 2741, gated onprofile.name.lower() == "elsevier"). None of these apply to the Springer/Nature path. There are zero occurrences ofbuy,add to cart,usd,shopping cart, or a price regex anywhere in the repo.Why this is wrong vs. AGENTS.md
AGENTS.md step 5 instructs the harness to "let the user complete institution login; wait + resume" when a closed-access page requires SSO. That step is only reached via
_complete_login_from_current_page, which is only called when_looks_logged_outreturns True. Because the Buy-PDF paywall makes_looks_logged_outreturn False, the SSO wait is skipped entirely and the Buy button is clicked instead — the opposite of the documented flow.Suggested fix
Non-prescriptive; happy to take either direction.
"buy article pdf","buy pdf","add to cart"(and optionally a price-with-intent pattern likeusd\s?\d/\$\d) tohard_wall_markers(lines 2703–2719); or, more robustly,sso_text_markersfallback is also consulted, e.g.return hard_wall_match or any(marker in text for marker in self.profile.sso_text_markers). This also catches future paywall phrasings that overlap with SSO link text._click_pdf_entry's generic loop (lines 2072–2092) — skip any:has-text('PDF')match whose visible text/href containsbuy,purchase,add to cart, or a price. The Elsevier path already does the equivalent at line 1034._click_sso_entry(line 814) already has generica:has-text('Access through your institution')selectors (lines 830–838) that route towayf.springernature.com; consider also guarding against the dead/institutional-login(404) href. This is secondary —_click_sso_entryis unreachable until fix Request for Collaboration Quotation #1 unblocks_ensure_login.domcontentloaded, so detection may need a short wait /locatorpoll before_looks_logged_outis evaluated, otherwise the markers may not yet be in the DOM.Environment
==GitHubmain, commit 2026-06-23)Workaround (current)
We run a small monkey-patch wrapper around the
PublisherBatchclass that overrides:_ensure_login— wait for late render, detect the Buy-PDF paywall, and if present call_complete_login_from_current_pageto drive SSO;_click_pdf_entry— reject any candidate whose text/href matchesbuy/purchase/add to cart/a price;_click_sso_entry— prefer thewayf.springernature.comWAYF link and skip the dead/institutional-loginURL;launched with
--no-broker. Verified to download the entitled article PDF (1.68 MB) after manual SSO completion. Happy to attach the patch if useful.Relevant files
instsci/publisher_batch.py—_ensure_login(678),_click_pdf_entry(2052),_looks_logged_out(2684), success-article branch (2702–2720), sso fallback (2721)instsci/publisher_profiles.py—SPRINGER_PROFILE(438),success_url_markers(445),sso_text_markers(454–459)tests/test_acs_batch.py—_looks_logged_outexercised only with RSC/Elsevier/ACS/Wiley profiles; no Springer/Nature paywall-detection coverageNotes for tests
Two existing intentional behaviors worth preserving when fixing this:
test_publisher_article_title_is_not_treated_as_auth_wall(test_acs_batch.py:277) asserts_looks_logged_outis False for an RSC page whose body contains the benign phrase "purchase options". This is likely why "buy article pdf" was never added. A fix should still pass this case — "Buy article PDF USD 39.95" (price + CTA verb) is a distinct, harder signal than the soft "purchase options" wording._looks_logged_outwithSPRINGER_PROFILEon anature.com/articles/...page containing "Buy article PDF USD 39.95" would directly cover this gap.