Skip to content

fix: wire three declared-but-not-enforced defects (research budget, link-pipeline cap, stale debug assertion) (#13013, #13021, #13037) - #13039

Merged
mrveiss merged 3 commits into
Dev_new_guifrom
issue-13013-13021-13037
Jul 30, 2026
Merged

mrveiss merged 3 commits into
Dev_new_guifrom
issue-13013-13021-13037

Conversation

@mrveiss

@mrveiss mrveiss commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Thinking Path

Three issues filed from prior sessions' reading, each in the same defect class -- something declared/asserted that was never actually wired to reality. Verified each premise against current code before touching anything (file:line), per this session's repeated finding that filed premises are sometimes wrong.

All three were fully deliverable -- none needed a scope-changing decision, so nothing was dropped.

What Changed

#13013 (services/research/orchestrator.py, orchestrator_test.py):

  • Added ResearchOrchestrator._record_truncation_if_needed(), called from _land_page right after a page is fetched: if len(markdown) > budget.max_content_chars (the same bound extract_claims slices to), appends the URL to budget.truncated_sources and logs it.
  • 2 new tests proving population on an oversized source and non-population on an in-budget one.

#13021 (media/link/pipeline.py, pipeline_test.py, autobot_shared/ssot_config.py):

  • New link_pipeline_max_content_bytes field on ssot_config (AUTOBOT_LINK_PIPELINE_MAX_CONTENT_BYTES, default 1_000_000) -- replaces the bare literal.
  • New _read_bounded_content() streams the fallback fetch response in 64 KiB chunks (mirroring web_fetch/fetcher.py._fetch_bs4's existing pattern) and returns None the instant the cap is crossed -- remaining chunks are never requested, so an oversized/slow-drip body is cut off mid-stream, not read fully then discarded.
  • A crossed cap logs "... REJECTED ... body exceeded max_content_length ... (distinct from a fetch/connection failure)" at WARNING, separate from the existing SSRF/connection/HTTP-error log lines.
  • 3 new tests: oversized body rejected + never reaches _parse_html; chunk consumption stops well short of the full stream once the cap is crossed (proves the cut, not just a flag); in-budget body still parses normally (regression guard).
  • Updated the 3 existing mock-response builders in pipeline_test.py (shared by TestLinkPipelineHttp and TestLinkPipelineJina's BS4-fallback tests, including PR fix(web_fetch): pin SSRF guard connect target in fetcher.py + link/pipeline.py (#13019) #13022's SSRF-pinning-adjacent fixtures) to also supply response.content.iter_chunked(), since the read path moved off response.text(). No assertions in those pre-existing tests changed.

#13037 (tools/tool_registry_debug_e2e_test.py):

  • Rewrote the two crash-prone/false-positive functions into 3 real, passing tests: Orchestrator has agent_registry (populated) and never tool_registry; the canonical get_tool_registry() singleton has tools wired (respond_conversationally present in get_available_tools()); and execute_tool("respond_conversationally", ...) actually runs end-to-end (mirrors the original script's _execute_planned_action intent, now via the real dispatch method).

Verification

python3 -m py_compile <all changed .py>                         # OK
python3 -m flake8 --max-line-length=120 <all changed .py>       # 0
python3 -m black --check --line-length=120 <all changed .py>    # unchanged

Per-issue tests:

services/research/orchestrator_test.py::TestTruncatedSourcesRecording   2 passed
media/link/pipeline_test.py::TestLinkPipelineContentLengthCap           3 passed
tools/tool_registry_debug_e2e_test.py                                   3 passed

Full related-scope sweep (services/research, media/link, tools/tool_registry*, api/knowledge_scrape_test.py, ssot_config_test.py):

528 passed (services/research + media/link + tools/tool_registry* + api/knowledge_scrape_test.py + ssot_config_test.py + tests/test_startup_imports.py)

cp-swapped baseline (origin/Dev_new_gui content restored in-place, tests re-run, then my changes restored via cp from a scratch copy -- no git stash):

Model Used

Claude Sonnet 5

mrveiss added 3 commits July 30, 2026 15:03
…truncation point (#13013)

extract_claims slices fetched content to budget.max_content_chars before
sending it to the LLM but the orchestrator never recorded which sources
that happened to. Record the source URL (and log) whenever the fetched
markdown exceeds the same content-char bound so truncation is now a
structured, testable field instead of only log-based observability.
…uring streaming (#13021)

media/link/pipeline.py declared _MAX_CONTENT_LENGTH but _fetch_and_parse's
BeautifulSoup fallback did an unbounded response.text() read. Enforce the
cap during the chunked read (mirroring web_fetch/fetcher.py._fetch_bs4) so
an oversized/slow-drip response is cut off mid-stream instead of read fully
into memory then discarded. The cap is now an env-sourced ssot_config field
(AUTOBOT_LINK_PIPELINE_MAX_CONTENT_BYTES) rather than a bare literal, and a
rejection logs distinguishably ("REJECTED ... distinct from a fetch/
connection failure") from genuine fetch/connection errors.

LinkPipeline/process_url currently has no production caller (api/
knowledge_scrape.py and peers call web_fetch.WebFetcher directly) so this
closes a latent resource-exhaustion gap rather than a live one -- fixed per
"never delete code, wire it in" ahead of any endpoint being wired to it.
…or.tool_registry premise (#13037)

Orchestrator has never had a tool_registry attribute (git log --follow shows
this script untouched except renames/relicensing since the project's
earliest history) -- it owns agent_registry for agent routing. Tool
execution is a separate pipeline owned by the canonical
tools.tool_registry.get_tool_registry() singleton, dispatched from
task_handlers/executor.py / api/agent.py. Rewrote the script's assertions
to match that real wiring (agent_registry on Orchestrator, get_tool_registry()
for tool dispatch/execution) instead of deleting them, preserving the
original intent of proving the tool-dispatch pipeline actually runs a tool
end-to-end.
@github-actions

Copy link
Copy Markdown
Contributor

✅ SSOT Configuration Compliance: Passing

🎉 No hardcoded values detected that have SSOT config equivalents!

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.

1 participant