fix(research): add a serial fallback, patch-bump the version, trim the body under target

The fan-out restored in 6683da5 had no degrade path for a target with no
spawn tool, which reproduces the silent degradation #116 was written
against. Step 4 now says to read serially and reduce each page to notes
when spawning is unavailable.

The change restores existing behaviour, so the version bump is a patch
(1.0.2) per skill-author's convention, not a minor. The body is trimmed
from 717 to under the 600-word ADR-0020 target without dropping any
instruction. ADR-0027 is updated to match.

Refs #116

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
This commit is contained in:
2026-09-21 07:33:14 +00:00
parent f48f3d9926
commit 1a66ee939a
2 changed files with 24 additions and 26 deletions

View File

@@ -19,8 +19,9 @@ serial behaviour followed the step text, which told the agent to go serial.
**Decision.** `research` keeps its `allowed-tools` list and gets its parallel fan-out back in steps **Decision.** `research` keeps its `allowed-tools` list and gets its parallel fan-out back in steps
4 and 5, with the "subagents read and summarise; the orchestrator writes every file" gotcha 4 and 5, with the "subagents read and summarise; the orchestrator writes every file" gotcha
restored (version 1.0.1 → 1.1.0). A skill body that instructs spawning must not be paired with text restored (version 1.0.1 → 1.0.2). A skill body that instructs spawning must not be paired with text
saying spawning is unavailable. saying spawning is unavailable. Step 4 carries a serial fallback for a target with no spawn tool, so
an unavailable spawn degrades visibly instead of silently.
The spawn tool is **not** added to the list. Its name is sourced for Claude Code (`Agent`) only; the The spawn tool is **not** added to the list. Its name is sourced for Claude Code (`Agent`) only; the
Copilot and Codex names are not known. On Claude Code, spawns therefore prompt instead of being Copilot and Codex names are not known. On Claude Code, spawns therefore prompt instead of being

View File

@@ -6,7 +6,7 @@ description: >-
documentation written from existing code or specs -> `write-docs`. Not a bug documentation written from existing code or specs -> `write-docs`. Not a bug
or incident -> `diagnose`. or incident -> `diagnose`.
metadata: metadata:
version: "1.1.0" version: "1.0.2"
category: research category: research
allowed-tools: allowed-tools:
- Grep - Grep
@@ -22,49 +22,46 @@ model: sonnet
## Gotchas ## Gotchas
- Never infer the output path. A run writes a directory's worth of files, and a guessed destination scatters them through someone's source tree. If the user named no path, stop and ask. - Never infer the output path: a guessed destination scatters a run's files through someone's source tree. If the user named no path, stop and ask.
- Write nothing outside the given output path. A file placed beside the agreed directory is one the user never asked for and will not think to look for. - Write nothing outside the given output path; the user never asked for a file beside it and will not look for one.
- Never write an empty topic file. A stub `troubleshooting.md` reads downstream as researched and closed. - Never write an empty topic file: a stub reads downstream as researched and closed.
- Subagents read and summarise; the orchestrator writes every file. A subagent that writes has no view of the other subagents' notes, so its files collide with theirs. - Subagents read and summarise; the orchestrator writes every file, so writers never collide.
- A Context7 response that is a "no results" message, a redirect notice, or header-only boilerplate is not coverage. A topic area counts as covered only when the response carries at least one substantive paragraph. - A Context7 "no results" message, redirect notice, or header-only boilerplate is not coverage; a topic is covered only by a substantive paragraph.
## Step 1 — Scope against the working directory ## Step 1 — Scope against the working directory
Search for existing use of the topic — imports, config files, version pins, reference files already written — and narrow the research to what is missing: the version actually in use, the topics not yet documented. Search for existing use of the topic — imports, config, version pins, reference files already written — and research only what is missing.
The default topic areas are `overview`, `installation`, `configuration`, `cli-reference`, The default topic areas are `overview`, `installation`, `configuration`, `cli-reference`, `api-reference`, `examples` and `troubleshooting` — one file each, only where content exists. If unsure what belongs in one, or a file outside that set is needed, read `references/topics.md`.
`api-reference`, `examples` and `troubleshooting` — one file each, and only where content exists.
If what belongs in one of them is unclear, or the topic needs a file outside that set, read
`references/topics.md` for the per-topic coverage table and the custom-topic naming rule.
## Step 2 — Resolve against Context7 ## Step 2 — Resolve against Context7
If the topic is a library, framework, or API and the user gave no starting URLs, call `resolve-library-id` with the topic name and the user's full question — match quality depends on the question, not the bare name — then `query-docs` once per default topic area. Record each response as a source with slug `context7-<library-slug>`, and mark which topic areas it covered — those skip the web reads at step 4. If the topic is a library, framework, or API and the user gave no starting URLs, call `resolve-library-id` with the topic name and the user's full question, then `query-docs` once per default topic area. Record each response as a source with slug `context7-<library-slug>` and mark the topic areas it covered; those skip step 4.
If the library does not resolve, or the user gave starting URLs, go to step 3. Explicit URLs are a source choice; do not second-guess them with a resolution attempt. If the library does not resolve, or the user gave starting URLs, go to step 3; explicit URLs are a source choice, so do not second-guess them.
## Step 3 — Discover sources ## Step 3 — Discover sources
If the user gave starting URLs, skip discovery: those URLs are the source list and go straight to step 4. If the user gave starting URLs, skip discovery: they are the source list, so go to step 4.
Otherwise, for every topic area Context7 did not cover, websearch for canonical documentation — `llms.txt`, official developer docs, and API references ahead of tutorials or blog posts. Collect three to five candidate URLs before reading any of them. Otherwise, for every topic area Context7 did not cover, websearch for canonical documentation — `llms.txt`, official docs and API references ahead of tutorials. Collect three to five candidate URLs before reading any.
If nothing usable comes back, stop and report what was searched, then ask for starting URLs rather than settling for tutorials. If nothing usable comes back, report what was searched and ask for starting URLs rather than settling for tutorials.
## Step 4 — Read the sources ## Step 4 — Read the sources
Spawn one subagent per URL, in parallel. Each fetches its page with `WebFetch` and returns notes by topic area plus the links worth deepening — never the raw page. The pages stay out of this context; only the notes come back. Spawn one subagent per URL, in parallel. Each fetches its page with `WebFetch` and returns notes by topic area plus links worth deepening, never the raw page. Only notes come back here. If no spawn tool is available, read serially instead, reducing each page to notes before fetching the next.
## Step 5 — Deepen ## Step 5 — Deepen
Spawn one further subagent per link worth following, again in parallel and again returning notes only. Stop a branch once its content turns repetitive or leaves the topic, and cap the whole step at roughly ten additional pages. Spawn one more subagent per link worth following, in parallel, returning notes only. Stop a branch once it turns repetitive or leaves the topic; cap the step at roughly ten additional pages.
## Step 6 — Write ## Step 6 — Write
Merge every set of notes, Context7 and web alike, by topic area, then write, in the output path: Merge all notes, Context7 and web, by topic area, then write in the output path:
- `<topic>.md` for each topic area that has content, default or custom. Frontmatter carries `topic:` (the filename without `.md`) and `source_keys:` (kebab-case slugs matching `sources.md`); the body is prose in `##` sections, with no inline URLs. - `<topic>.md` for each topic area with content, default or custom. Frontmatter carries `topic:` (filename without `.md`) and `source_keys:` (kebab-case slugs matching `sources.md`); the body is prose in `##` sections with no inline URLs.
- `sources.md`, always, one `##` section per source — including sources that yielded nothing — with exactly these four fields: - `sources.md`, always, one `##` section per source, including sources that yielded nothing, with exactly these four fields:
```markdown ```markdown
- **URL:** <full URL> - **URL:** <full URL>
@@ -73,8 +70,8 @@ Merge every set of notes, Context7 and web alike, by topic area, then write, in
- **Status:** `extracted` | `no content extracted` - **Status:** `extracted` | `no content extracted`
``` ```
Spell those four field names exactly as given. The downstream provenance validator matches them literally; prose in their place parses as nothing, and the check passes having verified nothing. Spell those four field names exactly: the provenance validator matches them literally, and prose in their place parses as nothing, so the check passes having verified nothing.
Read `references/file-format.md` when the four fields above do not settle the case: what a slug should be, the `context7-<library-slug>` slug and `context7:<library-id>` URL convention for a Context7 source, or what belongs in a topic body versus a verbatim copy of the source. Read `references/file-format.md` when the four fields do not settle the case: slug form, the `context7-<library-slug>` / `context7:<library-id>` convention, or what belongs in a topic body versus a verbatim copy.
If no topic area has content, write nothing at all, `sources.md` included, and report what was searched. If no topic area has content, write nothing, `sources.md` included, and report what was searched.