Repository navigation
Research runtime: fail closed when GPT Researcher reports zero sources - #759
Closed
seathatflowsinourveins wants to merge 3 commits into
Closed
seathatflowsinourveins wants to merge 3 commits into
seathatflowsinourveins wants to merge 3 commits into
Conversation
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 5, 2026
… "\n", fix the exit contract (#759 review) The command center's review of 93f3cbe (P3): - A query is written into the report frontmatter by cli.py's _yaml_quote (L220-222 at 0957c301), which escapes only backslashes and double quotes. A query with "\n" or "\r" could forge the sources_count line the guard reads, so the wrapper refuses it as a usage error (exit 2) before anything runs. - The guard now splits at "\n" only, as upstream joins the frontmatter (cli.py L245). str.splitlines() also broke at U+2028, which upstream leaves inside the query's line, so such a query could forge a count on a zero-source run. - The exit contract in the header: 2 is the wrapper's usage error, and the CLI's own status passes through unchanged (argparse's usage error is also 2; 124 from the watchdog; 125-127 when the timer or env cannot run). - sources_count counts URLs a run tried to read, not pages it read (skills/researcher.py L813-834, L911-913, L922-924, L1088-1098), so a count above 0 is necessary, not sufficient. The cause wording is now "probable": ddgs returns empty without raising both on a non-200 and on a 200 without hits. Tests: the stand-in CLI writes the run's own query through upstream's _yaml_quote. New cases cover line-break refusal, the U+2028 forgery and a CLI exit 2 passing through. The discriminating control runs this module against older wrappers in a mirror: ecfa112 fails 14 checks, 93f3cbe fails exactly the 4 new ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
seathatflowsinourveins
marked this pull request as ready for review
October 5, 2026 23:56
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
4 tasks done
seathatflowsinourveins
marked this pull request as draft
October 6, 2026 10:37
…rces Run 20261005T222529Z-1387309 exited 0 with sources_count: 0 and a 105-word report. After a successful CLI exit the wrapper now reads upstream's own count, the frontmatter sources_count of the one report the CLI writes under outputs/ (cli.py L209-245, L225, L332-336 at 0957c301), and exits 3 when there is not exactly one report, no single sources_count in a closed frontmatter, or zero sources. The CLI's own status (124 from the watchdog) still passes through, and the run directory is always printed. The retriever stays duckduckgo. GPT Researcher v3.7.0 (identical to main) calls ddgs text() with region 'wt-wt' and the default 'auto' backend and exposes neither to configuration. ddgs 9.16.0 is the newest release, and the region was declined upstream (deedy5/ddgs#417; PR #474 unmerged). The zero-source run came from per-engine throttling of this host (probe: brave 429, duckduckgo 202, google and mojeek 403, yahoo alone with results), which no pin removes. The wt.wikipedia.org DNS error is only the error the aggregator records. Keyless scholarly retrievers measured off-topic (arxiv), empty (openalex) or 429 (semantic_scholar) and would mask a dead web search under the guard. SearXNG through the searx retriever remains the owed durable route. Tests: the stand-in CLI writes upstream-shaped frontmatter; new cases cover zero sources, uncountable reports and status pass-through. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… "\n", fix the exit contract (#759 review) The command center's review of 93f3cbe (P3): - A query is written into the report frontmatter by cli.py's _yaml_quote (L220-222 at 0957c301), which escapes only backslashes and double quotes. A query with "\n" or "\r" could forge the sources_count line the guard reads, so the wrapper refuses it as a usage error (exit 2) before anything runs. - The guard now splits at "\n" only, as upstream joins the frontmatter (cli.py L245). str.splitlines() also broke at U+2028, which upstream leaves inside the query's line, so such a query could forge a count on a zero-source run. - The exit contract in the header: 2 is the wrapper's usage error, and the CLI's own status passes through unchanged (argparse's usage error is also 2; 124 from the watchdog; 125-127 when the timer or env cannot run). - sources_count counts URLs a run tried to read, not pages it read (skills/researcher.py L813-834, L911-913, L922-924, L1088-1098), so a count above 0 is necessary, not sufficient. The cause wording is now "probable": ddgs returns empty without raising both on a non-200 and on a 200 without hits. Tests: the stand-in CLI writes the run's own query through upstream's _yaml_quote. New cases cover line-break refusal, the U+2028 forgery and a CLI exit 2 passing through. The discriminating control runs this module against older wrappers in a mirror: ecfa112 fails 14 checks, 93f3cbe fails exactly the 4 new ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
seathatflowsinourveins
force-pushed
the
claude/ns2604-gptr-retriever-20261005
branch
from
October 6, 2026 10:38
7d01a9b to
19aeb85
Compare
seathatflowsinourveins
added a commit
that referenced
this pull request
Oct 6, 2026
… "\n", fix the exit contract (#759 review) The command center's review of 93f3cbe (P3): - A query is written into the report frontmatter by cli.py's _yaml_quote (L220-222 at 0957c301), which escapes only backslashes and double quotes. A query with "\n" or "\r" could forge the sources_count line the guard reads, so the wrapper refuses it as a usage error (exit 2) before anything runs. - The guard now splits at "\n" only, as upstream joins the frontmatter (cli.py L245). str.splitlines() also broke at U+2028, which upstream leaves inside the query's line, so such a query could forge a count on a zero-source run. - The exit contract in the header: 2 is the wrapper's usage error, and the CLI's own status passes through unchanged (argparse's usage error is also 2; 124 from the watchdog; 125-127 when the timer or env cannot run). - sources_count counts URLs a run tried to read, not pages it read (skills/researcher.py L813-834, L911-913, L922-924, L1088-1098), so a count above 0 is necessary, not sufficient. The cause wording is now "probable": ddgs returns empty without raising both on a non-200 and on a 200 without hits. Tests: the stand-in CLI writes the run's own query through upstream's _yaml_quote. New cases cover line-break refusal, the U+2028 forgery and a CLI exit 2 passing through. The discriminating control runs this module against older wrappers in a mirror: ecfa112 fails 14 checks, 93f3cbe fails exactly the 4 new ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
Author
|
Closed as superseded by #774, which changes both of this PR's files and keeps every line it added (command-center PR board ruling, 2026-10-10). Reopen if anything here is still needed. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Scope
What this PR changes:
tools/research/gpt_researcher.shnow FAILS CLOSED (exit 3, with a clear stderr message) when a research run reports zero sources, or when its report's sources cannot be counted. Before, an empty report read as success. The review round (7d01a9bc) does four things:\nonly, as upstream joins them;sources_countcounts attempted URLs.Tests cover zero sources, eight uncountable report shapes, line-break refusal, a U+2028 forgery and exit-status pass-through. The retriever stays duckduckgo; the config bytes and the install-plan row are unchanged.
Base commit:
ecfa11276(main after trading: NativeStack2604 research runtime, EdgarTools 5.60.0 (runtime and catalog), hash-pinned build backend #703). Head:7d01a9bc.Lane:
lane:foundation.Owned paths touched:
tools/research/gpt_researcher.sh,tests/test_research_entry.py.Diagnosis, from the pinned sources:
20261005T222529Z-1387309) most probably met search engines that were throttling this host.base.pyL68-70, L120-121) and on a 200 without hits (engines/wikipedia.pyL47-48), so the empty run's own log cannot tell the two apart.wt.wikipedia.orgDNS error comes from ddgs's wikipedia engine, whichautomode tries first, not as a fallback. That engine turns gpt-researcher's hard-codedwt-wtregion into a subdomain. ddgs surfaces the last exception it recorded; throttled engines return empty without raising.sources_countcounts the URLs a run tried to read, not the pages it read.skills/researcher.pyadds a URL when it is picked for scraping (L813-834), after a scrape whatever its outcome (L1088-1098), and for each prefetched result (L911-913, L922-924). A count above 0 is necessary, not sufficient.Open condition: this PR fixes detection only — a throttled run now exits 3, and "retry later" is the stopgap — and the next step is the SearXNG measurement decided at
docs/decisions/2026-10-01-new-wsl-definitive-defaults.md:80, proposed for the web-research layer sweep in the co-op's report (ledgerreport-ns2604-coop-20261005T225740Z); no bounded retry or backoff was added because the retriever swallows the search failure (duckduckgo.pyL50-52), so a retry would repeat the whole LLM run against the same probably throttled engines with no published window to wait for, and it would hide the failed attempt thatdocs/acceptance-evidence-policy.mdL60-62 asks us to preserve.SOTA sources
gpt_researcher/retrievers/duckduckgo/duckduckgo.pyL30-35 and L49-52: regionwt-wt; no backend or region setting reachable from config; a failed search is printed and returned empty;cli.pyL209-245 and L332-336: the report frontmatter'ssources_count, which islen(researcher.visited_urls);cli.pyL220-222:_yaml_quoteescapes only backslashes and double quotes. L245 joins the frontmatter at\n;gpt_researcher/skills/researcher.pyL813-834, L911-913, L922-924 and L1088-1098: whatvisited_urlsholds. L851+: every configured retriever runs for every sub-query.ddgs/ddgs.pyL88-96, L131-132 and L198-223: theautoengine order and last-exception surfacing;ddgs/engines/wikipedia.pyL35-39: region to language subdomain. L47-48: a 200 without hits returns empty;ddgs/base.pyL65-70 and L116-121: a status other than 200 (429, 202, 403) returns empty without raising;wt-wtis not a ddgs region); PR Skills trial review 2026-10-25 (window end): per-host checklist #474, open.timeout --help(uutils coreutils 0.10.0 on this host), section "Exit status". GNU coreutils'gtimeoutdocuments the same codes (coreutils/coreutils@e6c09ec0src/timeout.cL322-325):sources_countwhile web search is down;searxretriever: the durable keyless route, owed as a separately measured service, perdocs/decisions/2026-10-01-new-wsl-definitive-defaults.mdL80.Evidence-class table
python3 -m unittest -v tests.test_research_entryat7d01a9bc: 11 OK, exit 0. Discriminating controls, method below: againstecfa1127's wrapper, 14 checks fail; against93f3cbeb's, exactly the 4 new ones fail (exit 1 both)7d01a9bcand run with the installed venv over all 21 completed run directories under~/.local/state/new-wsl-native-stack/research/gptr: 20 pass, 1 rejected (20261005T222529Z-1387309,sources_count: 0)20261005T234148Z-2924799:bash tools/research/gpt_researcher.sh '<the empty run's query>'at7d01a9bc(wrapper sha2565bd4c76c44b03a84dfc676f1cade12eb7f030732c725e39c54c5b4c501dcbb09), 23:41:48Z-23:51:28Z, exit 0.sources_count: 9; reportoutputs/WSL_Settings_Guide.mdsha2569b95a02c4d9dade77e0d711a42df61fe747017d50f37cb619576aae7edc18b78; gateway sessiongptr-20261005T234148Z-2924799. Stdout tail below20261005T224417Z-1716824:"NTP leap smear guidance 2026"through the working-tree wrapper before93f3cbeb, which had the same guard result for well-formed frontmatter, 22:44:17Z-22:52:03Z, exit 0.sources_count: 7; report sha256dbbc2f3e5ca3482ffba29365579fa9a9c6495fa702d2e01f69e3d6d469db50d7. Stdout tail belowThe receipts are the run directories on this host (report and
config.json) and these stdout tails (home shortened to~):The re-run still logged two sub-queries with "No content found", a DuckDuckGo connection reset and the
wt.wikipedia.orgDNS error. Throttling stays; the guard makes a total failure visible.Discriminating control (
docs/acceptance-evidence-policy.mdL42-46). The test module fixesSCRIPTatROOT/tools/research/gpt_researcher.sh, withROOT = Path(__file__).resolve().parents[1](L21-22). Each control therefore builds a temporary mirror directory:git show <rev>:tools/research/gpt_researcher.shwritten into<mirror>/tools/research/gpt_researcher.sh;tools/research/gpt-researcher.config.jsonandtests/test_research_entry.pycopied in, plus an emptytests/__init__.py;wave2-records.json,integration-resolutions.json), at their repository paths.Then it runs
cd <mirror> && python3 -m unittest tests.test_research_entry:Local commands run
Decision record
None new. This is a defect fix inside the existing research-runtime decision. SearXNG is the recorded challenger and stays a separate measured adoption.
Host evidence
Not applicable.
Checklist
env -iand the keyless loopback placeholder.After landing, and only at a quiet point agreed with the command center, the co-op updates both installed copies, which still lack the guard:
~/.config/new-wsl-native-stack/gpt-researcher.sh, through the research-harnesses row's own install command (expect sha2565bd4c76c…from this head);1796303f.🤖 Generated with Claude Code