-
Notifications
You must be signed in to change notification settings - Fork 0
Completed II
Part 2 of the Completed list of finished ROADMAP items.
The three tier domain specialized architecture: Planner delegates to WebSearcher, AcademicSearcher, and PeerReviewer, and those in turn delegate to DocumentAnalyzer and DataAnalyzer. PeerReviewer is a Planner tier delegate for independent critique, not part of the Searcher to Analyzer chain. On 2026-07-13 a Builder Planner tier delegate was added (see the Build to Review to Fix loop entry below), and on 2026-07-14 a FindingsWriter Planner tier delegate was added the same way, one artifact earlier (see "Planner now only plans and delegates" below). Five Planner tier delegates exist now: WebSearcher, AcademicSearcher, PeerReviewer, Builder, and FindingsWriter.
The Planner now only plans and delegates, it cannot write any file. This was a 2026-07-14,
user driven design question: "the planner should only plan and delegate... giving the planner the
job of writing the findings will poison context." Previously the Planner wrote findings.md
itself, the only artifact writing job it still had after Builder was split out for
final_report.md, a real, inconsistent gap: a findings_ungrounded/missing_findings retry grew
the Planner's own conversation exactly the way Builder was invented to prevent for
final_report.md. Confirmed live the same day, independent of this fix: a benchmark run hit 4
consecutive findings_ungrounded retries and exhausted its budget with nothing ever written. The
fix was a new FindingsWriter Planner tier delegate, dispatched exclusively by the generalized
Write to Review to Fix loop when missing_findings/findings_ungrounded fires. FindingsWriter
never sees the Planner's conversation, its dispatch instructions are built entirely from
RunState's structured findings data, populated automatically by every Searcher and Analyzer
call, plus read_workspace_file/grep_workspace_file access to go deeper into a raw fetched
source if a summary isn't detailed enough. The Planner's write_workspace_file tool was removed
entirely, it's now structurally incapable of writing any file, the same way it's already
structurally incapable of researching.
This got live verified end to end across two real runs the same day: the architecture worked
correctly, FindingsWriter and Builder both dispatched via their own independent loops, and
PeerReviewer caught real issues in both, including a genuine findings.md problem that triggered
a real corrective re dispatch, and separately an unsupported citation in final_report.md. Tracing
one flagged citation to its root cause confirmed the layers really were independent, not just
redundant: findings.md correctly recorded that python.org's landing page has no biographical
content about Python's creator, a truthful negative finding, but Builder then cited python.org
in support of a creator claim anyway on its own initiative, a downstream synthesis error
introduced after FindingsWriter's own review, caught by a completely separate check. A new gap
surfaced by that same testing, not a flaw in the dispatch mechanism itself: on a run where Builder
repeatedly re committed the identical unsupported claim mistake across separate corrective
attempts, never actually fixing it, the Planner, resuming each time with no signal that a
Write to Review to Fix cycle just ran, kept deciding to delegate more research rather than
recognizing the problem was a downstream citation error, not a research gap. Because
delegate_tasks's own quota is independent of the completion check attempt limit, this let a
trivially simple factual query run 25 minutes and fetch 35 URLs before finally exhausting its
budget. The system's own safety net still worked correctly at the end, producing a real, honestly
labeled, mostly correct report instead of a silent failure or a hang, so this was an efficiency
gap, not a correctness regression. It got fixed the same day: run_completion_check now wraps its
retry loop so successful Builder and FindingsWriter dispatches continue straight into the next
completion check iteration instead of returning control to the Planner, so a persistently failing
chain now burns its retries entirely inside one call instead of wasting Planner driven "more
research" turns in between.
Also fixed around this time: a context_budget_chars blind spot for the classic
inject-into-Planner path. run_stream_chars only ever counted characters from the Planner's own
streamed generation, so a completion check nudge appended outside that stream loop was invisible
to the budget guard and could in principle grow the Planner's context unboundedly on repeat. Fixed
by measuring the character length of whatever run_completion_check actually appended and adding
it to the running total right after the call.
A batch of structural reliability fixes shipped around the same period: per attempt quota top up,
artifact quarantine before nudge, a structured _run_state.json including populated findings, a
real URL presence plus content level grounding check, and history scanning salvage for a narrated
but never written report, fixing an old single turn lookback bug that discarded good content when
the final retry produced empty text. Upstream verification also shipped: each Searcher
specialist's summary now gets grounding checked before it reaches the Planner, not just the final
report. A replan_action tool made the Planner's replanning decision a structured, checkable call
alongside its free text reasoning, though this was later deleted in the 2026-07-11 ponytail audit
as unused in practice. A persona brainstorming step had the Planner briefly reason from 2 to 3
relevant expert perspectives before planning non trivial queries, to widen slot coverage. HTML
boilerplate stripping got fixed on the primary fetch path, since previously only the BeautifulSoup
fallback stripped nav, footer, and script content while the primary markitdown path passed raw
chrome straight through. The DDGS search client moved to a per call instance instead of a shared
singleton, so concurrent specialist searches no longer share one client instance. An
extract_structured_data tool gave DataAnalyzer and DocumentAnalyzer a real tool level
distinction, not just a prompt driven one. A wiki index feature, a deterministic, engine
maintained cross run index independent of session isolation, was also deleted in the same ponytail
audit, since cross run state poisons benchmarks, the same reasoning as a rejected knowledge cache.
A heavy search mode searches deeper and auto fetches more top results per call instead of
fabricating fake query variant strings. A human in the loop gate reuses the existing approval
widget infrastructure to gate the Planner's write_todos. An MCP tool loader gives a generic
loader for the agent framework's native MCP tool types, connected per task, with nothing enabled
by default and two researched, ready to uncomment servers documented in the config template.
Readable run folder names replaced a bare unix timestamp with a slugified query plus timestamp. A
TUI click to copy fix tries the direct system clipboard before falling back to Textual's OSC52
escape sequence, which silently no ops in terminals that don't support it. TUI paste fixes flatten
a multi line paste into one line, since Textual's base input widget silently keeps only the first
line and drops the rest, and also debounce a same or prefix paste redelivered within half a
second, found live when a large pasted prompt showed up with a truncated repeat of its own opening
appended.
Model choice got re tested against this project's actual nested delegate_tasks schema. Several
models, devstral:24b, hermes3:8b, qwen2.5-coder:14b-instruct, llama3-groq-tool-use:8b, and
mistral:7b-instruct-v0.3-q5_K_M, were all tried and rejected for the Planner role at the time.
Devstral, despite roughly twice the parameter count, made zero real delegate_tasks tool calls
across a full 8 attempt run, narrating perfectly formatted JSON in a markdown code block instead of
emitting a real structured call, every single attempt, confirming bigger isn't automatically
better on this schema, the failure is a structured output habit, not a reasoning or capacity
limit. This was later superseded on 2026-07-11 when the 13 run Colombia B2B benchmark made
deepdelve-gpt-oss the default.
A per task fetch tracking race condition got fixed: the "URLs fetched by this task" delta used to
be computed via a before and after length check on the single run wide shared fetched URL list,
which races under concurrent delegate_tasks dispatch, confirmed live when a 3 task run produced 9
cross attributed findings instead of 3. Fixed with a proper per task scoped contextvar, verified at
10 task concurrency with zero duplication afterward. A delegation scope relevance check then
became possible on top of that fix, flagging a specialist's summary when nothing it actually
fetched mentions the entity its own delegation instructions required. A no_urls problem got its
own distinct completion check message with escalating language, handing back the exact fetched
URL list on repeat failures instead of reusing wrong citation wording that didn't fit a report
with zero citations. An explicit re delegation directive now forces delegate_tasks again when a
grounding check failure repeats with no new fetches since the last completion check attempt,
confirmed live to detect the exact failure it targets. delegate_tasks also started rejecting
unresolved placeholder tasks and same batch cross task dependencies before dispatching, both
patterns confirmed live via garbage search queries.
A wave of fixes around 2026-07-11 and 2026-07-12 tackled real fabrication and infrastructure gaps
found through a large live test battery, over 15 runs across factual lookups, comparative queries,
academic paper queries, current event queries outside training data, a TUI session, and several
real market research queries at varying scope. A full strict code audit around the same time found
two real bugs: the eval harness's find_latest_session still filtered on an old run_* prefix
left over from before the folder rename above, so no current run folder had ever matched it and
every eval run since had silently scored raw stdout instead of the real report artifact, and
remove_workspace_file's own docstring claimed it "mandates human oversight" while the config
template shipped with no permissions entry actually gating it. Both got fixed. A placeholder
detector false positive also got found and fixed via a real bad output diagnosis: a live "neglected
markets in Colombia" run had every single cited source turn out fabricated, root caused to the
Planner's real, well formed 12 task batch getting rejected wholesale because one task's name used
an ordinary numbered label, which falsely tripped a check meant for a task with no real name
anywhere. Facing the rejection, the model gave up delegating those 12 sectors entirely and
fabricated all of findings.md from memory instead. Fixed by checking only the instructions field
for the placeholder pattern, since that's the field that actually becomes a Searcher's query. Not
yet fixed at the time, same diagnosis: findings.md itself is never grounding checked at all, only
final_report.md is, so a Planner that abandons real delegation partway through a run can
fabricate findings.md wholesale with nothing structural catching it. Non URL pseudo citations
then got caught by a new line scoped check for a "Source:" labeled or "(Org, Year)" shaped
attribution with no URL on the same line, closing that gap.
A headless and headed browser fetch fallback got added for pages that bot wall a plain HTTP GET,
motivated by a live reported bug where real, citable papers on Springer, ScienceDirect, and MDPI
were all getting flagged as fake or stub sources. Root cause investigation found three distinct bot
wall signatures: Springer served a stripped shell to the plain fetch, ScienceDirect returned a
Cloudflare Turnstile challenge, and MDPI served an Akamai Bot Manager block. The fix retries once
via a real browser before giving up, when the plain fetch looks like a stub, reusing the same
boilerplate strip and markdown pipeline on the browser rendered HTML. It's a soft dependency that
fails open with zero latency cost if Playwright isn't installed. Confirmed live that a headed
browser beats headless: MDPI's block turned out to be a headless specific fingerprint check that
fires at the network level before any JS or DOM loads, so JS side stealth tweaks made zero
difference under headless mode, but a genuinely headed Chromium sailed straight through. The shipped
behavior tries headed first, using a real display or an auto started virtual one on Linux, and
falls back to headless only when no display is available at all. One more real bug got found and
fixed along the way: the boilerplate strip regex was a substring match, so it was deleting
Springer's actual 221 thousand character article body container because its CSS class happened to
contain the word "sidebar," silently leaving only the cookie consent banner behind, which then
passed the stub check on its own prose mass. Fixed with a size guard, since real chrome is never
that large. ScienceDirect turned out not fixable this way at all, root cause pinned down
precisely: it's gated by Cloudflare Turnstile, and exhaustive live testing found the challenge
iframe never resolves even after patient polling with a real headed browser, and spoofing
navigator.webdriver to undefined didn't help either, so the detection is deeper than any single
JS flag, almost certainly fingerprinting the Chrome DevTools Protocol connection Playwright itself
requires. The exact same URL, same machine, loads cleanly in the user's real, non automated
Firefox, ruling out IP reputation as the cause. This was deliberately not pursued further, since
defeating it would mean building and maintaining real anti detection tooling aimed specifically at
circumventing a publisher's bot controls, which doesn't belong in DeepDelve's shipped default
behavior, the same reasoning as declining to add CAPTCHA solving.
Three remaining structural fabrication gaps got closed in one pass on 2026-07-11, the first
Windows side session. First, a findings.md wholesale fabrication gate: run_completion_check
now flags a Pass 1 file with zero cited URLs or where not one cited URL matches a real fetch,
quarantining it and forcing re delegation, deliberately laxer than the strict per URL final report
check since Pass 1 notes legitimately mention unfetched snippet URLs. Second, structural exclusion
enforcement: delegate_tasks extracts explicit exclusions from the original query and skips
matching tasks individually rather than rejecting the whole batch, because the placeholder detector
incident had shown wholesale rejection makes the model abandon delegation and fabricate. Third,
unresolved referent rejection: a live delegated task, "Summarize its headline feature," searched
the web with no idea what "its" meant and returned Microsoft Research patent statistics as
Python's headline feature, so short instructions leaning on a bare pronoun with no proper noun,
digit, or quote anchor are now rejected with guidance to restate the subject.
The Windows migration, a dual boot setup on the same NTFS drive, shared the Ollama model store via
an explicit path, fixed a cp1252 UnicodeEncodeError in headless mode with a UTF-8 reconfigure
guard, and pinned the doc extras actually used since markitdown[all] silently downgrades to a
stub package on Windows with newer Python. The full pipeline got re verified live on Windows with
ROCm on an RX 9060 XT 16GB.
A production batch landed on 2026-07-11, all validated live during the 13 run benchmark day: a
findings.md existence gate requiring Pass 1 before final_report.md is accepted, --resume-run
to reattach an interrupted run, a TUI intake clarifier that fails open, a settings.max_run_minutes
run budget, --depth quick|standard|deep presets, a repeatable --seed-url, a finish line summary
plus --list-runs, TUI follow up continuity for Q&A mode on an existing report, a
regulation_id_check for a law number cited to a source that never actually mentions that number,
and quarantined draft restore at final verdict, since earlier runs had ended with a real draft
sitting in a rejected attempt file while salvage delivered meta narration instead, now the draft
wins, loudly labeled.
A completion check refactor on 2026-07-12 replaced a roughly 250 line if/elif verdict chain in
tui.py, which had shipped the same swallowed elif bug twice, with a data driven check list in
src/engine/completion.py where the first verdict wins and there are no elif headers left to
swallow, pinned by a 10 row verdict matrix in the test suite. A Windows workspace escape bug in
_get_safe_path got fixed the same day: joining a base path with a drive qualified filename
discards the base entirely, so drive lettered or drive relative filenames could escape the
workspace, since the Planner has write_workspace_file. Drive lettered names are now rejected
outright with an abspath containment check added on disk workspaces. A documentation update pass
followed, flipping the config template default to deepdelve-gpt-oss and syncing the README and
ROADMAP.
A context budget endgame guard shipped, since local models run at a fixed context size with no
context accounting, so on overflow Ollama silently truncates from the top, eating the system
prompt mid run, indistinguishable from model collapse. A new settings.context_budget_chars
counts text, tool args, and results per agent stream, and on overshoot the turn gets cut with one
forced wrap up turn, verified live with a tight 3000 character budget producing an honest "budget
exhausted" report instead of silent truncation. A grounding layer hardening batch the same evening
shipped several fixes together, all validated live: stub fetch detection recording soft 404 or
paywall shells so grounding checks refuse them outright, a fix so the injected line 1 header's own
URL slug no longer counts as source content, a charset fix so HTML gets decoded by its real
encoding with stale meta tags scrubbed, citation format enforcement flagging a section with 3 or
more figure bearing lines and no citations, a URL prefix boundary fix so a fetched URL no longer
grounds a fabricated URL that merely starts the same way, the grounding check's own master switch
actually being honored, and a platform independent drive letter guard.
Repo governance and CI landed the same day, triggered by an external audit's one genuinely real finding, that the repo was public with no license. A LICENSE file (MIT), a CI workflow running install, lint, and the structural test suite on every push or PR to main, and a pragmatic lint config narrowed to real issues rather than style noise all shipped together, along with floor and ceiling dependency pins and a lockfile snapshot. The rest of that audit's "critical" findings got checked directly against the code and found false or already solved.
An academic or literature review output mode shipped on 2026-07-12, triggered by a real gap: a
live sales forecasting query got a properly structured literature review paper from DeepSeek while
the local model collapsed on the same query through DeepDelve. A new settings.report_style
option, orthogonal to depth, rewrites the Planner's report structure instructions into a
literature review shape, with Abstract, Introduction, thematic sections, synthesis, benchmarking
summary, challenges, and a References list, modeled on a reviewed external repo's own template,
and swaps the citation format to author-year in text plus a numbered References list. It also
carries that repo's Anti Leakage Protocol, preferring findings.md over parametric memory and
writing "Not covered by this run's research" instead of inventing a section. The grounding layer
gained a parse_academic_references function mapping author-year keys to their References entry's
URL, and every line scoped check now resolves academic citations through it alongside the existing
inline URL format. A real bug got caught building the test coverage: a line with two author-year
citations only had its first one checked, since the regex used .search() instead of
.finditer(), so a real citation earlier on a line could mask a fabricated one later on the same
line. A fresh audit pass then caught a higher severity bug in the same feature before any live
run: the citation detector required every token before the comma to start with an ASCII capital,
so it silently failed to even detect "et al.," ampersand, or accented surname citations at all,
exactly the forms the feature's own prompt tells the model to use, breaking grounding in both
directions. This got fixed too, along with a related mis keying bug where a reference entry's own
title could shadow its real author and year. A live validation run produced the literature review
shape correctly end to end, with citations resolving with zero false positives; the run's one real
failure was the pre existing hard URL presence gate correctly catching a genuine citation accuracy
slip, not a defect in academic mode.
A checkmark on error TUI bug got fixed on 2026-07-12: ToolCallWidget.set_result always rendered a
green checkmark regardless of the result text, so a real run showed a read_workspace_file call
marked complete despite returning an error. A new error detection helper now drives both the TUI
glyph and a new tool error counter. A fuzzy filename fallback for read_workspace_file/
grep_workspace_file traced the root cause of a run that gathered substantial research but never
produced a report, since 16 percent of workspace read calls used a garbled or truncated filename
reconstructed from memory by a sub agent one hop removed from the original fetch, each failure
burning a turn and a quota unit, cascading into abort exceptions. A new fuzzy resolver using a
conservative single best match threshold now auto resolves these instead of erroring. Structured
_run_state.json logging expanded the same day, persisting full completion check verdict detail
per attempt, a tool error counter with samples, and a subagent label disambiguator so repeat
dispatches of the same task name get a readable suffix instead of colliding in post hoc analysis.
A /resume-run slash command finally got added to the TUI too, since it had been CLI only for a
full prior session unnoticed, and the exact scenario it exists for, a quarantined run with real
work already on disk, actually happened with no TUI path to reach it. This prompted two new
standing rules: mandatory TUI/CLI feature parity checks, and tracing a change's blast radius across
sibling surfaces before calling it done.
An answer mode shipped the same day too, from the dzhng/deep-research reference project: a third
report_style option for a short, direct answer with no section headings and an inline citation
instead of a References list. Live validated: the first attempt hit a real unsupported claim
quarantine since the model's citation format deviated from spec, the completion check cycle
correctly caught it and nudged a rewrite, and the second attempt passed with a clean short answer.
A TUI ProcessingWidget timer leak got fixed the same day, caught live: a run's final turn, the
model's response after tool quotas were exhausted with nothing left to say, streamed zero content,
so the widget's stop method, gated on the turn's first content token, never fired, and its elapsed
seconds counter kept climbing indefinitely well past the point the run had already reached its
final verdict, making a genuinely finished run look stuck. Fixed with unconditional cleanup once
the stream is guaranteed exhausted, not just the reactive first token path.
A cross model benchmark against NVIDIA NIM ran the standing benchmark query against DeepSeek V4
Pro, a Nemotron Super 49B model, and gpt-oss-20b, all hosted. DeepSeek crashed on an uncaught 429
mid run, Nemotron made zero real delegate_tasks calls and fabricated placeholder citations, and
gpt-oss-20b was the only one to reach a clean pass, though thin, with one real citation carrying a
wrong paper title. None beat the local gpt-oss:20b, confirming a single general purpose LLM
handling research, synthesis, and verification end to end has a real ceiling here, not just a
local model weakness. This directly motivated two tracks of "specialized non LLM component instead
of another LLM call" work, informed by FActScore's decompose then verify pattern and HALT-RAG's
combine lexical and NLI finding. Track 1, NLI based grounding verification, added a small cross
encoder entailment classifier that runs only on claim lines that already passed the cheap term
overlap check, catching a citation with the right source and shared terms but a wrong specific
detail, like a paper title quoted with one word swapped, exactly the NIM benchmark's failure above.
This was the project's first ML or NLP dependency, and a real footprint issue got caught and
fixed, since the naive install pulled the full CUDA torch build at around 6GB even though nothing
here touches a GPU, switched to a roughly 200MB CPU only wheel instead. Track 2, fetch time
metadata extraction, pulled title, author, and published date from the same parse the boilerplate
stripper already builds, eliminating a mechanical "extract title and authors" sub agent dispatch
pattern that had fired 13 times identically in one day's logs.
An uncaught crash on malformed tool call retry exhaustion got fixed the same period, plus TUI
parity added: a huge write_workspace_file argument got truncated mid JSON by the model, the
existing 2 retry recovery correctly retried twice, but the third consecutive occurrence hit a bare
raise that killed the whole run with an uncaught error, at attempt 8 of 8, after 18 real sources
already fetched and 5 report attempts already written to disk. The CLI now degrades to the same
final verdict path used for other budget exhaustion instead of crashing, and the TUI gained the
identical retry then degrade logic it previously had none of at all for this failure class. A tool
call validation error visibility gap also got found and fixed: a full day log cross reference
found a generic "Argument parsing failed" error was the single most common error signature of the
day, with every one having its actual cause silently stripped, because the agent framework's
detailed error config was never enabled. Turning it on also helps the model self correct on retry,
not just diagnostics. Two of that error's concrete root causes got fixed the same commit: one tool
was missing a required search pattern argument in many occurrences, and another was missing an
optional filename argument that got made truly optional with an auto derived default.
A second live confirmed completion check stall, missing_findings, got fixed: a verification run
produced literally zero content in response to this nudge for 6 consecutive attempts, then
genuinely self corrected with real content on the seventh, a different failure shape from
missing_artifact's, which never self corrected without help. The wording now escalates after the
first occurrence and, from the second on, hands the model its own actual fetched URLs verbatim as
proof real material exists, deliberately without missing_artifact's aggressive early cutoff,
since that would have killed this exact run's real recovery before its genuine success at attempt
7.
The Builder sub agent and Build to Review to Fix loop, shipped 2026-07-13, was the direct fix
for the context growth risk noted above. The user's own diagnosis: the Planner's own conversation
only ever grows across a run, since no compaction exists in the underlying session framework, so
every completion check retry historically meant appending another nudge and re showing the model
its own rejected drafts, a documented failure mode called context poisoning. This maps onto the
established Plan and Execute agentic pattern and reuses the existing delegate_tasks mechanism,
which already gives every dispatched sub agent a genuinely fresh, isolated context, so the fix was
routing report writing retries through that mechanism instead of the Planner's own conversation,
not inventing a new one. A new Builder role writes and rewrites final_report.md from
findings.md, and the Planner no longer writes or delegates the report at all, its own
instructions end at Pass 1. Completion check problems now get classified as either Builder
fixable, meaning rewriting the report from the same findings.md with no new research needed, or
Planner escalated, meaning genuinely more or different research is needed, which only the Planner
can decide to delegate. For Builder fixable problems, the system dispatches a Build, Review, Fix
sequence directly: Builder rewrites the artifact, a fresh PeerReviewer dispatch reviews the
result, with a required "REVIEW: CLEAN" or "REVIEW: ISSUES FOUND:" opening line so the caller can
branch without another LLM call, and Builder gets exactly one corrective re dispatch if flagged.
None of this touches the Planner's own conversation state.
Two live validation runs confirmed this end to end. A simple factual query hit missing_artifact
on attempt 1, dispatched Builder, dispatched PeerReviewer (clean, no corrective pass needed), and
completed cleanly in 691 seconds with the Planner's own conversation untouched. The standing
heuristics algorithms sales forecasting benchmark, a genuinely hard, three way AND query with no
single source satisfying all three criteria, saw the loop fire correctly 3 times on real
unsupported problems, each time dispatching Builder then PeerReviewer without touching the
Planner's conversation. A new finding, not previously possible to observe: on later attempts,
Builder itself hit the same "narrate instead of write" failure the Planner used to be prone to,
because Builder shares the run's single write_workspace_file quota pool with the Planner and
every prior Builder dispatch, and by that point the pool was exhausted, with Builder's own text
saying so explicitly. The pre existing quarantine restore fallback caught this correctly at the
final verdict, restoring the best surviving draft with its loud unresolved check banner, an honest
labeled recovery rather than a silent failure or a lost draft. The net assessment: the mechanism
itself works as designed, but it doesn't rescue a query where the source material genuinely
doesn't exist, and it surfaced a new, real quota sharing constraint under heavy retry load.
Phase 1 of an approved 6 phase plan: claim level grounding upgrade, combining atomic claim
decomposition with per claim evidence binding. Found on 2026-07-13, informed by FActScore's
decompose then verify pattern and a claim evidence provenance paper (later corrected in title on
2026-08-17 during a broader literature completeness audit, "From Fluent to Verifiable:
Claim-Level Auditability for Deep Research Agents," not the earlier miscited title, the author and
substance were always correct). The prior claim_grounding_problem compared a whole line's terms
against the union of every source cited anywhere on that line, a real gap when a line carries two
distinct claims each with its own citation, since a shared generic term between claim A and claim
B's source could mark both claims "supported" even though claim B's own citation didn't actually
back it. A new decompose_claim_segments splits a line into atomic segments at each citation
boundary, mechanical regex token splitting with no NLP and no new dependency, and
claim_grounding_problem now checks each segment only against its own bound citation's source. A
residual gap in the sibling NLI and topical relevance checks, which had the same latent whole line
overlap gap, got closed the next day, 2026-07-14.
check_excluded_topic, report write time enforcement of query exclusions, closed a gap where
delegate_tasks already skipped dispatching a task whose own topic matched an explicit query
exclusion, but did nothing to stop that topic showing up as its own section in the final report
anyway, recalled from a sibling task's tangential findings. The new check reuses the exact same
exclusion parser, now applied to the report's own heading sections, deliberately heading scoped
rather than whole document substring matching, so a topic mentioned once in passing prose doesn't
false positive.
Phase 2 of the 6 phase plan: cross source contradiction detection, FEVER style, depending on
Phase 1's claim segmentation. A new find_cross_source_contradictions builds an index of every
other fetched source's own claims, pairing each subject with its nearest same line figure by
character distance rather than a full cross product, then for each report claim segment checks
whether a different fetched source, one not cited on that segment, reports a same kind but
numerically different figure for the same subject, unmentioned anywhere else in the report.
Distinct from a plain unsupported claim, since the cited source really does support the claim,
this instead catches the report silently picking a side of a real disagreement between two fetched
sources without saying so. Isolated sanity checks during development caught and fixed a real bug
before it shipped: an early version paired every subject with every number on a line regardless of
kind, so a line naming both a year and an unrelated percentage spuriously "contradicted" any other
source's differing percentage for a totally unrelated reason. A second real bug got found live on
2026-07-14 during Phase 6's TUI smoke test: a citation attribution appearing only inside a source
line, and dozens of times across a long fetched Wikipedia article as bare attribution, image
captions, or reference list entries, never as the subject of an actual claim, got treated as a
genuine claim subject and paired with an unrelated nearby year, firing the same phantom
contradiction after every single Builder rewrite, a structurally unfixable, non converging retry
loop. This got caught only because the user pushed back on accepting the loop at face value rather
than assuming it was a stream handling issue. Fixed with a new helper that treats a line as
bibliographic rather than a claim if fewer than 8 letters of real text remain after stripping
markdown links and a leading bullet or "Source:" marker. A fresh live re run of the identical query
converged in 1 Builder cycle and about 5 minutes, versus 5 plus cycles and never converging before.
Phase 3 of the 6 phase plan: xQuAD style search result diversity reranking. DDGS already ranks
by its own relevance signal, but several near duplicate results for the same angle commonly
dominate the top of that ranking. A new _diversity_rerank greedily reorders web_search's
results by marginal new aspect term coverage instead of raw rank, DDGS's own top result always
stays first, then each subsequent pick is whichever remaining result adds the most new aspect
terms. Pure reranking, no LLM call, no new dependency, applied once right after search health
recording and before the auto fetch slice, improving both the auto fetch selection and the
returned snippet ordering.
Phase 4 of the 6 phase plan: a topical relevance cross encoder reranker. A third stage grounding check, layered after term overlap and entailment checks, reusing the same evidence set but asking a different question: is the cited source actually about the same subject as the claim, not just lexically overlapping and non contradictory? This fixes an acronym collision case where a term overlap check passes and an unrelated sentence about a place doesn't contradict an algorithm claim, it's just unrelated, so neither upstream layer can catch it. A second cross encoder checkpoint got loaded through the already installed sentence transformers library, no new pip dependency. This got verified against the real checkpoint, not just the mocked test: the irrelevant pair scored 0.023 and the relevant pair scored 0.997, a huge margin either side of the 0.1 threshold, confirming the design assumption was correct before it ever reached a live run. A real bug got caught and fixed during this same pass too: the new check's config gate wasn't included in the test suite's existing mocking guards, so the first full suite run after wiring it in silently loaded the real, unmocked reranker model, the exact anti pattern that guard was built to prevent.
Phase 5 of the 6 phase plan: coverage accounting, or ResearchMap. Distinct from every other
completion check, since those all verify content that already exists is properly grounded, this
instead asks whether the Planner's own top level delegated research plan actually paid off, since a
report can be perfectly grounded yet still be thin because most of the Planner's own delegated
angles came back with nothing usable and got silently dropped rather than surfaced or retried. This
was deliberately built entirely from already reliable, model independent structural data instead
of a new Planner authored schema, after investigating and explicitly ruling out relying on the
todos file, since that's free text with only a prompted, zero code validated convention. A new
RunState.coverage() reuses two already existing, engine populated primitives to compute total,
covered, ratio, and uncovered task names over distinct top level task names. The new
check_thin_coverage isn't Builder or FindingsWriter fixable, since fixing thin coverage needs new
delegation, which only the Planner can decide, so it falls through to the classic
inject-into-Planner path by design, and it's conservative by construction, firing only when a
majority of top level tasks came back with no real source and there are enough of them for that
ratio to mean anything.
Live verification the same day found 2 more real bugs, both fixed and live confirmed. First, the
sub agent timeout deadline fix from an earlier phase was never actually live, it existed in the
config template but nothing back filled an existing user's real config file, so it was silently
disabled the whole time, and every earlier "live verified" confirmation of that fix had only been
true because the key had been temporarily test added to the config and reverted afterward. This
prompted a new standing rule: new settings keys must be grepped in the live config, not just the
template, before a dependent fix counts as verified. Second, _dispatch_writer_review_fix's
corrective Fix pass had no evidence base of its own, since its second dispatch is a fresh sub agent
with zero memory of the first Write dispatch, and the fix instructions said to use "the real source
material you were given" but never actually included it, harmless for Builder, whose source is a
real re readable file, but fatal for FindingsWriter, whose source material only ever existed as a
string in the first dispatch's prompt. Confirmed live: a corrective FindingsWriter dispatch burned
its entire turn hunting for guessed, nonexistent filenames instead of writing a fix. Fixed by
re appending the original write instructions to the fix instructions. Third,
check_thin_coverage itself false positived on the project's own internal Write to Review to Fix
dispatches, since Builder, FindingsWriter, and PeerReviewer are dispatched directly from the
Planner's own top level context rather than through delegate_tasks, landing them at the same
depth as a genuine top level research task, structurally indistinguishable by depth alone. Fixed
with a new constant naming those three roles explicitly and skipping finding recording for them.
Phase 6, also called item B4: unify run_cli/run_agent's stream iteration and retry logic.
Done. The two genuinely duplicated pieces between headless and TUI mode got extracted into shared
helpers: an async generator racing each update against an optional wall clock deadline, replacing
the CLI's inline manual loop, and a pure decision function for the malformed tool call retry
pattern, previously copy pasted between both call sites and once found missing from the TUI
entirely. This was the last open phase of the 2026-07-14 six phase plan, all six phases are now
done.
A claim_grounding_problem false positive on citation only sub bullets got fixed on
2026-07-14. Root caused a live Eiffel Tower smoke test failure that burned its entire 8 attempt
retry budget on unsupported claims, even though both flagged claims were verbatim in the fetched
source, a genuine false positive, not model fabrication. This project's own Builder output shape
puts a claim on one line and its citation on a separate "Source:" sub bullet, and that bare sub
bullet was being processed as its own claim segment, with the salient term extractor pulling an
editorialized anchor phrase out of the citation's own link text as if it were a checkable fact,
then failing it because that exact phrase, the writer's own paraphrase, doesn't appear verbatim in
the source. A helper that already existed for exactly this line shape, built earlier the same day
for the cross source contradiction work, just hadn't been applied here yet. Now it is, in both
places. A live end to end re verification of the exact same query produced zero false positive
occurrences, converging cleanly in under 500 seconds versus over 1000 seconds of wasted grinding
before.
Immediate narration salvage inside _dispatch_writer_review_fix. Implemented on 2026-07-18,
targeting the "writer role finishes its turn without ever calling write_workspace_file" failure
class at its root. The project already had a salvage function for a model that narrates a complete
report as chat text instead of calling the tool, but it only ran as a last resort at final verdict
time, and only for a missing final report, not for a missing findings file, which was the case
that actually burned one candidate model's full 8 attempt budget. This is now checked immediately
after every Write dispatch: if the required artifact is still missing but the dispatch returned at
least 200 characters of real text, that text gets persisted as the artifact right away, clearly
flagged as an auto recovered draft, and flows into the same review and grounding cycle a genuine
write would, instead of looping blind on a file that will never appear on its own. A live re test
against the exact case that motivated it surfaced a more precise root cause than assumed: that
particular model's dispatches returned a genuinely empty response, confirmed via the persisted
session log, zero events, no tool call, no text at all, not a narrated report, the same symptom
already documented for a different candidate. Salvage correctly declined to act, since there was
nothing above the 200 character floor to recover, rather than fabricating content from nothing. A
full re run confirmed the diagnosis further: still missing_findings, all 8 attempts, and the
final corrective pass decoded over 45,000 tokens continuously, blew past its own context window
once, and was still running when checked, a second, independent confirmation of the runaway
generation failure class this project had already fixed the missing guard for elsewhere. The final
verdict for that specific candidate: genuinely no recoverable content to give in the FindingsWriter
role, empty responses and runaway non answers alike, a harder failure than "narrates instead of
writing," and no structural salvage can rescue a dispatch that produces nothing at all.
Shared quota pool starvation, fixed on 2026-07-18. This ring fences a task's remaining quota once it's shown real fetch activity this dispatch: the first time a tool call would exceed the shared cumulative limit for a task that's already fetched something real, it grants one small one time top up instead of hard blocking, bounded so it can only fire once per tool per run. This directly targeted a documented failure where a dispatch had fetched 2 real sources, then hit a bare "Quota reached" wall before ever synthesizing them.
A Brave Search MCP country parameter rejecting real countries, including Colombia, got
fixed the same day. The MCP server's country param turned out to be a fixed 37 code enum that
doesn't include Colombia's code at all, confirmed by reading the installed package's own schema
source, which broke every Colombia targeted search outright. A wrapper strips an out of enum
country value before it reaches the subprocess, falling back to an unscoped search instead of a
hard rejection, scoped only to specs whose server name contains "brave" so it can't affect any
other MCP server.
The completion check remediation loop exhausting read_workspace_file's quota before the final
Builder pass gets to read what it needs, found live on 2026-07-20 during the routing
classifier's second re test run. A run hitting multiple completion check remediation cycles
dispatches a corrective sub agent per cycle, each burning read quota against the same shared pool
as normal first pass work, and 3 remediation cycles in one run exhausted the quota, so the final
corrective Builder pass silently dropped an entire correctly researched section rather than
erroring loudly. Fixed on 2026-07-21 with a new helper mirroring the existing writer side quota
top up, applied at both Builder and FindingsWriter remediation dispatch sites.
Two shipped TUI quality of life improvements, moved from Pending during the 2026-07-21 status
audit, the rest of that backlog stayed open. AgentMessageWidget click to copy landed on
2026-07-14, mirroring the existing user message widget's copy pattern exactly, one click copy on
the agent's actual answers and reports, not just the user's own prompt. Right click paste landed
the same day, a read side mirror of the existing copy helper, using the system clipboard tools with
no OSC52 equivalent since that escape sequence is write only, wired into a right click on the
prompt input, inserting at cursor or replacing the current selection. Live verified: a real copy
then paste round trip returned the exact original text. This required installing the actual
clipboard tools on the dev machine, since neither was present beforehand, meaning copy had been
silently falling back to an unverified OSC52 path and paste had had no fallback at all, worth
checking for on any fresh setup, since without one of these two tools paste always shows a
"clipboard paste failed" warning instead of pasting.
History
Model Research
Reviews & Audits
Reference