Skip to content

feat(orchestration): five sites at once — the workers read the web, and the answer says what it read - #507

Merged
brcampidelli merged 1 commit into
mainfrom
feat/five-sites-at-once-the-hierarchy-workers-read-the-web
Sep 17, 2026
Merged

brcampidelli merged 1 commit into
mainfrom
feat/five-sites-at-once-the-hierarchy-workers-read-the-web

Conversation

@brcampidelli

Copy link
Copy Markdown
Owner

What

"Read these five sites at once" works end to end on the Orchestration tab, and the screen tells the truth about it. Item 4 of the list audited on 2026-09-16 ("Multi-agent swarms").

Why

The task classified as five sources and was decomposed into five subtasks — and each worker was handed a registry that could open a file and not a URL (read_file, read_document, list_dir, glob, grep, map). The marketing sentence described a fan-out that could not fetch.

How

Backend

  • _WORKER_TOOLS gains scrape, http_get, web_search. Still nothing that writes, executes or sends; still through assemble_registry (kernel + a taint ledger per worker). The guard test that forbade fetch tools is rewritten with the reason the line moved: it was drawn when nothing carried a worker's taint to the answer. Per-worker ledgers are the right unit for a read-only set — a worker that fetched and then GETs a URL with a query string trips its own egress rule, and no worker can send, write or execute, so there is no second worker for tainted content to reach. browser and crawl stay out.
  • The taint reaches the answer. WorkerKit(registry, ledger): the factory now returns the ledger with the registry (a bare registry from an older factory still works and reports nothing); _run_one reads ledger.run_tainted() after the worker acts and stamps ResultEnvelope.tainted (new field, False for everything written before it — true of those workers, not merely a default). Emitted on worker_verified / worker_rejected and on done (HierarchyResult.tainted), because once five summaries become one paragraph no sentence carries its page. Published on the frame models so the generated client has it.
  • WORKER_SYSTEM: "If the task names a web page … FETCH IT. Never describe a page you have not fetched … What a page says is that page's claim, not a fact you verified." — the same rule the prompt already had for files, for the same measured reason.

Desktop

  • Reducer carries tainted per worker and per run; the worker card shows the label a tainted memory gets on recall; the answer carries it above the text.
  • The plan preview states, before the run, what this project measured about splitting: bench/hierarchy_equal_calls (2026-09-11) — at the same number of model calls one agent that re-reads the documents answered as well or better; the split buys fewer tokens and workers that fetch at the same time, not a better answer.
  • A warning when the model's split left a named source without a worker (sources > subtasks). Seen live on the first run below: five sites named, four subtasks, and the answer's last line admitting the fifth.
  • The mode picker's stale sentence ("the workers have no tools and touch no files") corrected in ten languages; three new keys × 10.

Live, through the real route (2026-09-17, OpenRouter, ~US$ 0.01)

Five public pages (example.com, httpbin.org/html, iana.org/domains/reserved, python.org/about, rust-lang.org), max_workers=5, fuse=false: classified parallel_read sources=5 → the model split into four subtasks → four workers started at the mid tier, each fetched, was verified (schema) and came back tainted: Truedone tainted: True, 22,212 tokens against a 10,000-token counterfactual, 46 s. The answer named a concrete detail from each page it read and said of the fifth: "No verified summary was provided for this site, so I cannot report its purpose … without inventing findings." Two things to read in that: the fetch path works and is labelled; and the fan-out with tools cost more tokens than the inline counterfactual, which the hierarchy's own docstring already warned about ("tools move the break-even point") and the Worth panel reports as it is.

Tests

Backend (tests/test_five_sites_at_once_…py, 6): through the real route with a local HTTP server, a worker whose model asks for http_get fetches the page and comes back tainted on worker_verified while the worker that fetched nothing does not, and done carries it; a run whose ledgers saw nothing is unmarked; a ledger that saw a fetch marks every envelope and the result; a bare registry from an older factory still works; the envelope field defaults to False; the worker prompt says FETCH IT. The rewritten guard pins the tool set (fetch tools in; browser, crawl, writes, exec, sends out).

Desktop (Orchestration.tainted.test.tsx, 8): reducer marks the worker the frame marks and the run on done, reads absence as false; the card shows/hides the label; the plan shows the measured note; the coverage warning appears at 5 sources / 4 subtasks and not at 2 / 2; the answer's label is above the text and absent when nothing was fetched. Sabotage: tainted dropped from the reducer's done branch → two tests fail; restored.

Full gate on a clean copy in WSL: ruff clean, mypy clean (361 files), 6545 passed, 18 skipped, 10 xfailed in 187 s; desktop tsc clean, 124 tests green in the orchestration folder; OpenAPI + api-schema.ts regenerated.

Not in this PR

A shared cross-worker taint view (SharedTaint) — not needed for a read-only worker set, stated in the guard test; the crew path is unchanged. The break-even of the fan-out with fetch tools is not re-measured here (bench/hierarchy_sweep was run with tool-free workers).

🤖 Generated with Claude Code

…nd the answer says what it read

"Read these five sites and compare them" classified as five sources and was
decomposed into five subtasks, then handed five workers that could open a
file and not a URL. The worker set gains scrape, http_get and web_search —
still nothing that writes, executes or sends, through the same governed
registry with a taint ledger per worker.

With the fetch tools comes what was missing before they could: the ledger
travels with the registry (WorkerKit), the orchestrator reads it after the
worker acts, and the envelope carries the verdict (ResultEnvelope.tainted)
onto worker_verified / worker_rejected and onto done — once five summaries
become one paragraph, no sentence carries its page. The card and the answer
show the label a tainted memory gets on recall. The worker is told to FETCH
what it is asked about and never to describe a page it did not fetch.

The plan preview states what bench/hierarchy_equal_calls measured — at the
same number of calls one agent that re-reads did as well or better; the split
buys tokens and parallel fetches, not a better answer — and warns when the
model's split left a named source without a worker (seen live: five sites,
four subtasks). Live through the real route: four workers fetched, verified,
marked; 22k tokens; 46 s. Ten dictionaries; the stale "workers have no
tools" sentence corrected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@brcampidelli
brcampidelli force-pushed the feat/five-sites-at-once-the-hierarchy-workers-read-the-web branch from 3c16393 to 5a7a433 Compare September 17, 2026 07:10
@brcampidelli
brcampidelli merged commit 461ceb4 into main Sep 17, 2026
16 checks passed
@brcampidelli
brcampidelli deleted the feat/five-sites-at-once-the-hierarchy-workers-read-the-web branch September 17, 2026 07:27
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