build/skills/research/SKILL.md
Use when questions.md is approved and the QRSPI pipeline needs objective codebase and web research — dispatches parallel specialist subagents per question, collates per-question findings into research/summary.md
npx skillsauth add dfrysinger/qrspi-plus researchInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
PRECONDITION: Invoke qrspi:using-qrspi skill to ensure global pipeline rules are in context. (Idempotent on session re-entry. Subagents are exempt — SUBAGENT-STOP in using-qrspi handles that.)
Announce at start: "I'm using the QRSPI Research skill to investigate the research questions."
Objective exploration driven by the research questions. Gathers facts, not opinions. Each question gets a focused specialist agent with the right tools for its research type. Research isolation is structural — no research subagent ever sees goals.md.
Required inputs:
questions.md with status: approvedIf questions.md doesn't exist or isn't approved, refuse to run and tell the user to complete the Questions step first.
Read config.md from the artifact directory to determine whether Codex reviews are enabled. If config.md doesn't exist, default to codex_reviews: false.
Parallel specialist subagents (ISOLATED — structurally enforced). One subagent per question (or per small group of related questions). A collation subagent assembles the per-question ## Summary blocks into _collated.md at the end; the orchestrator then renames _collated.md to summary.md via a single mv Bash call.
CRITICAL: goals.md is deliberately withheld from ALL research subagents. This is enforced structurally — subagent prompts contain only the question(s) assigned to them. goals.md is never passed to any research subagent, including the collation subagent. This prevents confirmation bias.
questions.md — extract each numbered question with its research type tag| Research Type | Agent Tools | Focus |
|--------------|-------------|-------|
| [codebase] | File read, grep, glob | Read code, trace logic flows, map architecture. Report file:line references. |
| [web] | Web search, web fetch | Search competitors, libraries, best practices, docs. Report URLs and sources. |
| [hybrid] | All tools | Compare local implementation against external standards/alternatives. |
{ABS_RESEARCH_DIR}/q{NN}-{type}.md using the Write tool. The orchestrator passes the absolute path into the subagent prompt; subagents do NOT return findings as text. The q*.md filename pattern is intentionally outside the Claude Code 2.1.x subagent-guardrail blocklist (filenames whose stem starts (case-insensitive) with report, summary, findings, or analysis), so direct write succeeds.Any artifact in the QRSPI run directory governed by status: draft → approved frontmatter promotion (goals, design, structure, phasing, plan, parallelization, roadmap, future-goals, and any future artifact adopting this lifecycle) describes the current state of decisions. The reader is a downstream agent or future maintainer.
(Excludes by design: SKILL.md files — skills carry rule rationale legitimately; feedback/*.md — the designated home for dialogue exhaust; reviews/**/*.md — finding rationale; config.md — non-narrative.)
Litmus test (apply to every paragraph before write). Two filters, in order:
A sentence that only makes sense as a delta from a prior state is dialogue exhaust — strip it.
Permitted substantive content (do NOT confuse with dialogue exhaust):
## Trade-offs Considered — substantive content about the decision space, not about the document's history)Named antagonist patterns — strip on sight, substitute as shown:
| Antagonist pattern | Recognize by | Replace with | |---|---|---| | Session / drafting notes | "Rule X drafting note," "this collapsed from 3 to 1 because…" | Nothing — delete. If a fact matters, embed inline in the decision. | | Version-history narration | "earlier draft said X," "previously," "originally," "pre-cleanup" | Nothing — git history holds versions. | | Inside baseball | text addressed to "us" / "the author," meta-explanation of the document's own structure ("this section is split into A and B because…") | The decision the structure expresses — without the structural explanation. | | Compaction-loss recovery notes | "this nuance was almost lost during…" | Nothing — if the nuance is needed, the rule itself carries it. | | Failure-modes-prevented lists | bullets that justify why a rule exists rather than state what to do | Strengthen the rule's wording; delete the justification list. |
Decision-process history (drafts, review rounds, feedback applied, compaction recovery) lives in feedback files, review findings, PR descriptions, and git history — never in the artifact.
Inputs: Only the assigned question(s) from questions.md. NO goals.md. NO raw feedback/research-round-*.md files (raw feedback may carry user goals/intent — forwarding it to a research subagent breaks the research-isolation invariant). The orchestrator also passes the absolute output path ({ABS_RESEARCH_DIR}/q{NN}-{type}.md) and, for grouped questions, the full set of question IDs the report should cover. On re-dispatch via Rejection path 2, the orchestrator passes a sanitized defect summary it authors itself from the user's feedback — defect-only bullet points (e.g., "missed the auth module", "TL;DR is missing", "broken file:line citation"). Goal-bearing or intent-bearing language is stripped before the summary reaches the subagent.
Dispatch — for each question (or grouped set of related questions), dispatch Agent({ subagent_type: "qrspi-research-specialist", model: "sonnet" }) in parallel via concurrent Agent tool calls. The agent body (loaded by the runtime) carries the full research-agent rules, output-format template, and contract; the dispatch prompt carries only the parameters below.
Dispatch parameters (per specialist):
question_body: wrapped body of the assigned research/q*.md question(s) between <<<UNTRUSTED-ARTIFACT-START id=question>>> and <<<UNTRUSTED-ARTIFACT-END id=question>>> markers; for grouped questions, all assigned question texts concatenated within the wrapperoutput_path: absolute path the specialist writes its report to (<ABS_RESEARCH_DIR>/q{NN}-{type}.md)question_ids: comma-separated numeric IDs the report should cover (e.g., 3 or 3,7)defect_summary (re-dispatch via Rejection path 2 only): orchestrator-authored sanitized defect summary; goal-bearing/intent-bearing language strippedDirect-write contract (unambiguous default). Per-researcher subagents write their q*.md report directly to output_path via the Write tool. They do not return report content as text. Text-return is not used anywhere in the research pipeline — the collation subagent also direct-writes (to the research/_collated.md staging filename, which the orchestrator then renames to research/summary.md). The staging-filename pattern exists precisely to avoid text-return through main chat. If the orchestrator ever omits output_path from a per-researcher dispatch, that is a dispatch defect — fix the orchestrator, do not fall back to text-return.
Summary-last authoring order. The per-question report template places the structured summary block (TL;DR / key findings / surprises / caveats) at the top of the file — that is the consumer-facing reading order. Authoring order is the inverse: investigate first, draft the full report body, then author the summary block last, then place it at the top of the file. Do not generate the summary from intent before the body is complete.
Research-isolation invariant — the specialist dispatch carries NO companion_goals, NO other-question content, and NO feedback/research-round-*.md files. This is structurally enforced — the agent body refuses goals.md / cross-question content if it ever appears in the dispatch prompt. Research isolation prevents confirmation bias.
Every qrspi-research-specialist dispatch is observed at the dispatch boundary by a post-output citation-density validator. The validator runs AFTER the specialist's q*.md report is written and BEFORE the report is read by the collation subagent or any downstream consumer. The floor that the validator measures against is the validators.citation_density_floor: key in config.md (default 0.05 — see the schema documentation in skills/using-qrspi/SKILL.md (T01) for the key's full semantics, the citation-counting rule, and the rationale for the default value).
Above-floor result. The report proceeds unchanged. The collation subagent reads it on the same schedule as any other specialist output. No re-run, no diagnostic, no telemetry rerun-count increment.
Below-floor result (first occurrence). The dispatch re-runs the specialist EXACTLY ONCE on the trusted model (the role's trusted_path: route from config.md's model_routing: table, OR the trusted-tier default from the routing matrix in skills/implement/SKILL.md § G5 Initial Routing Matrix). The re-run carries identical question_body and question_ids parameters as the original dispatch — only the (provider, model) pair changes. The orchestrator increments the per-task citation_density_rerun_count field in this task's telemetry record (see skills/implement/SKILL.md § Per-Task Telemetry Emission).
Below-floor result (re-run also below floor). The validator emits a loud diagnostic naming the below-floor density value, exits non-zero (propagating the failure signal to the Implement orchestrator), and does NOT silently forward the below-floor output to downstream consumers. The non-zero exit is observably distinct from the success path — it is NOT a zero-exit-with-empty-body. The Implement orchestrator treats the non-zero exit as a specialist-dispatch failure and may retry on a different topic angle, escalate to opus, or proceed with degraded output per its BLOCKED escape hatch; the validator never silently degrades.
The dispatch-wrapping contract that consumes this hook (when the wrap fires, how the telemetry rerun-count is incremented, what the orchestrator does with the non-zero exit) is authored in skills/implement/SKILL.md § Specialist Citation-Density Validator. This Research section documents the producer-side hook contract that Implement consumes.
After all per-question research completes, dispatch a lightweight collation subagent whose ONLY job is to extract the ## Summary block from each q*.md file verbatim and assemble them into the staging file research/_collated.md (which the orchestrator subsequently renames to research/summary.md via a single mv Bash call). This is mechanical extraction — not synthesis, not re-prose. Each per-question report already carries a structured TL;DR / Key findings / Surprises / Caveats block at its head (see Per-Researcher Subagent template above); the assembled output is just those blocks stitched together in question order, plus a short Cross-References section.
Why a collation subagent (not orchestrator-direct, not synthesis):
q*.md files into ITS context, then exits. Main chat never loads the full report bodies. If main chat did the collation directly, all q*.md contents would persist in main chat's conversation history and slow every downstream stage — Design proposes better architecture on a lean context.## Summary blocks are the canonical at-a-glance summary by contract.summary.md matches the Claude Code 2.1.x subagent-guardrail blocklist (filenames whose stem starts (case-insensitive) with report, summary, findings, or analysis), so the subagent cannot Write to it directly. To avoid text-return (which would route the assembled content through main chat's context, defeating the hygiene goal), the subagent instead writes to a staging filename outside the blocklist — research/_collated.md — and the orchestrator then renames it to research/summary.md with a single mv Bash call. The mv adds only the command string and a tiny confirmation to main chat's context, not the file body. The public artifact name (summary.md) is unchanged, preserving all downstream references in other QRSPI skills.Inputs to the collation subagent: All research/q*.md files. NO goals.md. NO questions.md. NO raw feedback/research-round-*.md files (raw feedback may carry user goals/intent — forwarding it breaks research isolation). On re-dispatch via Rejection path 1, the orchestrator passes a sanitized defect summary it authors itself from the user's feedback — bullet points covering collation-output defects in either dimension collation owns: extraction fidelity (e.g., "Q5 TL;DR was misquoted in the prior _collated.md") OR Cross-References authoring (e.g., "missing link between Q3 and Q7 findings"). Goal/intent-bearing language is stripped. The verbatim-extraction contract still binds — extraction-fidelity defects are fixed by re-extracting per the Procedure, NOT by paraphrasing.
Dispatch — Agent({ subagent_type: "qrspi-research-collator", model: "sonnet" }). The agent body (loaded by the runtime) carries the verbatim-extraction rules, the procedure, the output-file shape, and the contract-violation list. The dispatch prompt carries only the parameters below.
Dispatch parameters:
qfile_paths: list of absolute paths to research/q*.md files (passed as paths, not bodies — the collator Reads each file itself; this is required by the staging-filename + verbatim-extraction contract and keeps research bodies out of main chat's context)output_path: absolute path to the staging file (<ABS_RESEARCH_DIR>/_collated.md) — NOT summary.md (the Claude Code 2.1.x subagent-guardrail blocks summary.md direct write; the orchestrator renames _collated.md → summary.md after the subagent returns, per the staging-rename pattern documented above)defect_summary (re-dispatch via Rejection path 1 only): orchestrator-authored sanitized defect summary scoped to either dimension collation owns (extraction fidelity OR Cross-References authoring); goal-bearing/intent-bearing language strippedResearch-isolation invariant — the collator dispatch carries NO companion_goals and NO companion_questions. NO raw feedback/research-round-*.md files. The agent body refuses any of those if they appear in the dispatch prompt.
Orchestrator handling: When the collation subagent returns confirmation, run a single Bash call to rename the staging file to its final name: mv {ABS_RESEARCH_DIR}/_collated.md {ABS_RESEARCH_DIR}/summary.md. If the subagent returned a contract-violation report instead of writing _collated.md, re-dispatch the offending researcher (per the specialist dispatch above) with the orchestrator-authored sanitized defect summary, then re-dispatch collation. Isolation-violation handling is separate — see § Isolation-Violation Orchestrator Handling below.
All three research subagents (specialist, collator, reviewer) run a Pre-Flight Isolation Check on their incoming dispatch prompts (see the ## Pre-Flight Isolation Check (FAIL-LOUD) section in each agent body). If a goals-content or cross-question pattern is detected, the subagent does NOT write its expected output — it returns a single-line text response with the load-bearing prefix RESEARCH-ISOLATION-VIOLATION: followed by the pattern name and short evidence (≤80 chars).
Orchestrator detection: when any research subagent returns text instead of writing its expected file, inspect the first line for the prefix RESEARCH-ISOLATION-VIOLATION:.
Orchestrator response (fail-loud, not retry-with-same-leak):
field-name-leakage ⇒ a forbidden parameter name (companion_goals, companion_questions, etc.) was attached; filename-leakage ⇒ a goals.md / questions.md payload was wrapped into the prompt; goals-heading-leakage / goal-framing-triplet ⇒ goals body content was smuggled into question_body, companion_qfiles, or defect_summary; cross-question-leakage ⇒ q*.md payloads from outside the assigned question_ids reached the specialist; questions-compendium-leakage ⇒ questions.md reached collator/reviewer; sanitization-bypass ⇒ the orchestrator-authored defect_summary still carried goal/intent prose.question_body containing only the assigned IDs.defect_summary from the raw feedback, stripping goal/intent prose more aggressively. If the raw feedback is entirely goal-bearing, surface the issue to the user (per Rejection Behavior step 3 edge case) rather than re-dispatching with an empty summary.Why this matters: the prior prose-only "report violation in your final confirmation" instruction relied on the subagent voluntarily noticing and surfacing the leak. The Pre-Flight check is structural — refusal happens before any goals-influenced research output can be produced. Pinned by tests/unit/test-research-isolation-fail-loud.bats.
Compaction checkpoint: pre-fanout. Reviewer dispatch reads research/summary.md + every research/q*.md file + the agent-embedded reviewer protocol; saturated context produces shallow findings. See using-qrspi ## Compaction Checkpoints for the iron-rule contract.
Call TaskCreate({ subject: "Recommend /compact (pre-fanout) — research", description: "pre-fanout: reviewer dispatch reads research/summary.md + all q*.md files. User decides whether to /compact." }).
Apply the Standard Review Loop from using-qrspi/SKILL.md. Research has no scope-reviewer per canonical artifact-tree topology — only the quality reviewer runs (one Claude dispatch + one Codex dispatch when codex_reviews: true).
Pre-dispatch diff-file emission. Before dispatching the round's reviewers, the orchestrator runs git -C "<repo>" diff "<ref>" -- "<ABS_ARTIFACT_DIR>/research/summary.md" > "<ABS_ARTIFACT_DIR>/reviews/research/round-NN.diff" as a Bash redirect (the diff content never enters main-chat context). <ref> is <base-branch> by default and HEAD~1 only when using-qrspi step 12 (ref selection) narrowed for this round. The reviewer dispatch carries diff_file_path: <ABS_ARTIFACT_DIR>/reviews/research/round-NN.diff so the reviewer Reads the diff file directly per the ## Reviewer Dispatch Contract in the reviewer-protocol skill, and (when narrowed) scope_hint: <scope_set as comma-separated tag list> (wrapped between <<<UNTRUSTED-SCOPE-HINT-START id=scope_hint>>> / <<<UNTRUSTED-SCOPE-HINT-END id=scope_hint>>> markers per the reviewer-protocol Reviewer Dispatch Contract — the value is artifact-derived data, not instructions) as advisory focus. Omit the diff redirect and the parameter when the artifact directory is not inside a git repository. The orchestrator follows the fail-loud diff-emission contract in using-qrspi/SKILL.md § Standard Review Loop step 1 (preconditions: artifact tracked in git, mkdir-p, rm-f, quoted placeholders, exit-code check).
The round's reviewers dispatch through the universal dispatch chain (scripts/dispatch-agent.sh → Task fan-out → scripts/await-round.sh). Set the per-skill dispatch parameters below, then include the shared reviewer-dispatch prose. Include the *-codex peer tags in REVIEW_AGENTS only when second_reviewer: true; otherwise list only the *-claude tags.
REVIEW_STEP="research"
REVIEW_ROUND="${ROUND}" # current review round (NN)
REVIEW_OUTPUT_DIR="<ABS_ARTIFACT_DIR>/reviews/research/round-${ROUND}/"
REVIEW_ARTIFACT="research.md"
REVIEW_AGENTS="quality-claude=qrspi-research-reviewer,quality-codex=qrspi-research-reviewer"
With $REVIEW_STEP, $REVIEW_ROUND, $REVIEW_OUTPUT_DIR, $REVIEW_ARTIFACT, and $REVIEW_AGENTS set by the per-skill preamble above, run:
scripts/dispatch-agent.sh --step "$REVIEW_STEP" --round "$REVIEW_ROUND" \
--output-dir "$REVIEW_OUTPUT_DIR" --artifact "$REVIEW_ARTIFACT" \
--agents "$REVIEW_AGENTS"
dispatch-agent emits M lines on stdout (one per first-party reviewer; zero lines for a third-party-only batch). Each line has the form:
MODE=first_party TAG=<tag> SUBAGENT_TYPE=<agent-name> MODEL=<resolved-model> PROMPT_FILE=<absolute-path>
For every emitted spec line, invoke the Task tool with these arguments (parse the line as space-separated KEY=VALUE pairs; values contain no spaces):
subagent_type = the SUBAGENT_TYPE value, verbatimmodel = the MODEL value, verbatimprompt = the literal string "DISPATCH_FILE=<PROMPT_FILE-value>" — a single-line env-var-style reference; the prompt argument has no other contentInvoke all M Task tool calls in parallel in one orchestrator response (one Task call per spec line). The reviewer agent body's first instruction is to Read its DISPATCH_FILE — do not pre-Read the file yourself; the dispatch context belongs in the subagent's window, not the orchestrator's.
Iron law (orchestrator-side dispatch contract): invoke the Task tool exactly once per emitted spec line, with SUBAGENT_TYPE, MODEL, and PROMPT_FILE copied verbatim. Skipping a line, deduplicating across lines, modifying any value, or substituting a different subagent_type is a contract violation. The dispatch manifest ($REVIEW_OUTPUT_DIR/.dispatch-manifest.json) records expected dispatches; the apply-fix step's "expected tag produced no output" diagnostic catches missed or mis-routed Task invocations.
After all Task tool calls return (Task tool is synchronous; first-party subagents have written their per-finding files to disk by the time Task returns), drain any third-party background dispatches and finalize the round:
scripts/await-round.sh --round-dir "$REVIEW_OUTPUT_DIR"
await-round is no-op-safe — first-party-only rounds still call it; it returns immediately after reading the manifest. It writes a small $REVIEW_OUTPUT_DIR/.round-complete.json summary and (for third-party dispatches) materializes per-finding files via third-party-finding-splitter.sh. It does NOT echo captured subagent payloads (CD-1 #4 output-bound contract).
Then read $REVIEW_OUTPUT_DIR/.round-complete.json and the per-finding files as needed for apply-fix. The raw per-reviewer prompt content (assembled by dispatch-agent into PROMPT_FILE) never enters the orchestrator's context — only the small spec lines + the small DISPATCH_FILE references passed to Task.
Because Research involves multiple subagents, rejection has two paths depending on user feedback. In both cases:
feedback/research-round-{NN}.md (see using-qrspi Feedback File Format) — this is the durable record. The raw feedback file is NEVER passed to a research subagent — that would break research isolation, since user feedback can carry goals or design intent.Rejection path 1 — Collation problem ("the Cross-References miss an important link", "Q3's summary block is being misquoted in summary.md"):
q*.md files + the orchestrator-authored defect summary scoped to either dimension collation owns: extraction fidelity OR Cross-References authoring. The subagent re-extracts ## Summary blocks verbatim (fixing any extraction-fidelity defects by re-extracting, not paraphrasing) and re-authors Cross-References to address the cited defects.Rejection path 2 — Underlying research problem ("Q3's findings are incomplete — the researcher missed the auth module", "Q5's summary block doesn't match the contract template"):
q*.md directly per the Per-Researcher template.summary.md from the updated per-question reports.Ask the user which path applies when they reject.
Present research/summary.md to the user. Note that this is ~200 lines — much easier to review than code. Always state the review status when presenting: either "Reviews passed clean in round N" or "Reviews found issues in round N which were fixed but not re-verified."
On approval, if reviews have not passed clean, note this and ask if they'd like a review loop before finalizing. Then write status: approved in frontmatter.
When config.md carries pipeline: quick, the human-approval gate is skipped after any review round (initial or post-fix) that produces zero kept findings. When this branch fires, status: approved is written to research/summary.md frontmatter automatically without waiting for user input.
Verifier-gate precondition. "Zero kept findings" is satisfied only when the verifier has affirmatively confirmed the count — a vacuously-zero count from an undispatched verifier does NOT satisfy the gate and surfaces the round to the user as unverified (matching the HARD-GATE contract in skills/implement/SKILL.md). If config.md is missing or unreadable when this branch is evaluated, the auto-approve branch does NOT fire — the orchestrator surfaces a named diagnostic and falls through to the standard human-approval gate (fail-loud, not silent fallback to either pipeline mode). The gate passes when ANY of the following hold for the current round's directory (reviews/research/round-NN/):
.score.yml sidecar file exists in the round directory AND every sidecar evaluates to no kept-blocker findings per the verifier's scoring rubric (see agents/qrspi-finding-verifier.md and skills/implementer-protocol/SKILL.md). A zero-byte sidecar does not constitute verifier affirmation and the gate does NOT pass. Full sidecar schema validation is the verifier's contract (see agents/qrspi-finding-verifier.md); this skill assumes well-formed sidecars. ORround-NN-verifier-disabled.md marker file is present in the round directory AND the marker conforms to the canonical schema defined in skills/implement/SKILL.md HARD-GATE (a marker failing schema validation, or whose round identifier does not match the current round, is treated as absent). ORconfig.md carries verifier_enabled: false. When this condition satisfies the gate, the orchestrator MUST append an audit-log entry before writing status: approved — recording: timestamp, run slug, step name (research), and branch label (auto-approve-verifier-disabled-config). The audit entry is written to the cascade audit log if one exists, otherwise to the round directory. An attempt to auto-approve via verifier_enabled: false without successfully writing this audit entry MUST abort with a named diagnostic (fail-loud, matching the audit-write precondition philosophy in skills/implement/SKILL.md HARD-GATE). This path is a deliberate operator-level configuration, not a default; the round appears in the review log as verifier-disabled, not as a normal clean round.When none of these hold (no sidecars with affirmative zero-kept-findings content, no valid schema-conforming marker for the current round, and verifier_enabled is absent or true), the gate does NOT fire; the review round surfaces to the user as unverified and the standard human-approval gate runs.
Post-fix round behavior. If a fix round still produces kept findings, the auto-approve branch does NOT fire. The orchestrator surfaces the remaining kept findings to the user. The branch fires only when the most recent review round — initial or post-fix — produces verifier-affirmed zero kept findings.
Specialist dispatch cap. When pipeline: quick, the count of dispatched research specialists is capped at the question_budget value from config.md. If questions.md contains more questions than question_budget, the orchestrator dispatches at most question_budget specialists (grouping lower-priority questions into existing dispatches rather than adding new ones). This cap honors the quick-fix scope-tightening contract: the question_budget field is written to config.md by the Goals skill at run creation when pipeline: quick (default value: 5). Subject to the schema-level ≤50 ceiling enforced by Goals (see the Goals skill's question_budget field validation); Research treats any value outside the validated range as a precondition violation and halts with a named diagnostic. The question_budget value is read once at run start; subsequent edits to goals.md are not re-applied to the in-flight research cap. If question_budget is absent from config.md when Research dispatches in pipeline: quick, the dispatch halts with a named diagnostic; the cap is REQUIRED for quick-fix Research — no silent default to an arbitrary value.
Full pipeline unchanged. When pipeline: full, the human-approval gate runs as before and no specialist dispatch cap applies — the branch is inert and the user must explicitly approve.
If the artifact directory is inside a git repository, commit the approved research/summary.md, all research/q*.md files, and the reviews/research/ directory (per-round per-reviewer files; see using-qrspi → "Commit after approval (when applicable)").
Compaction checkpoint: pre-handoff. Research approved; the next skill (typically Design) reads research/summary.md + every prior approved artifact + reviewer findings on a fresh context. See using-qrspi ## Compaction Checkpoints for the iron-rule contract.
Call TaskCreate({ subject: "Recommend /compact (pre-handoff) — research", description: "pre-handoff: next skill reads research/summary.md + prior artifacts + reviewer findings. User decides whether to /compact." }).
REQUIRED: Invoke the next skill in the config.md route after research.
auth/middleware.ts:45-67)## Summary blocks, or adds Cross-References that re-narrate findings rather than naming connections| Rationalization | Reality |
|----------------|---------|
| "The researcher needs goals for context" | No. Research isolation prevents confirmation bias. The questions provide all the context needed. |
| "This opinion is well-supported" | Opinions are for Design, not Research. Report the facts and let Design interpret. |
| "Collation can lightly rephrase for flow" | No. Collation is verbatim extraction of per-question ## Summary blocks. Any rephrasing is a contract violation; the only authored content is the short Cross-References section. |
| "One researcher can answer multiple questions" | Group related questions only. Over-consolidation reduces depth. |
| "The web research is thorough enough without URLs" | Uncited claims are unverifiable. Every web finding needs a source URL. |
Good research finding (objective, factual):
Q4: What Redis-based rate limiting algorithms exist?
Three common algorithms:
Fixed Window — Count requests in fixed time intervals. Simple but allows bursts at window boundaries. Used by GitHub API (https://docs.github.com/en/rest/rate-limit).
Sliding Window Log — Store timestamp of each request, count within sliding window. Precise but memory-intensive (O(n) per client). Described in https://blog.cloudflare.com/counting-things-a-lot-of-different-things/.
Token Bucket — Tokens added at fixed rate, consumed per request. Allows controlled bursts. Used by AWS API Gateway (https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html). The
rate-limiter-flexiblenpm package (https://github.com/animir/node-rate-limiter-flexible) implements this with Redis backend.
Bad research finding (opinionated):
Q4: Rate limiting algorithms
You should use the Token Bucket algorithm because it's the best approach for APIs. Fixed window is outdated and sliding window is too complex.
The bad example makes recommendations ("you should"), value judgments ("best", "outdated", "too complex"), and cites no sources.
The two override-critical rules for Research, restated at end:
Research isolation is structural — goals.md is NEVER passed to any research subagent. This includes the collation subagent. Subagent prompts contain only the assigned question(s) — or, for collation, only the per-question q*.md files — plus, on re-dispatch, an orchestrator-authored sanitized defect summary with goal/intent-bearing language stripped. Raw feedback/research-round-*.md files are NEVER passed to subagents. Goal leakage produces confirmation-bias-driven research that selects for the conclusion the goals already implied.
Facts only — no opinions, no recommendations, no value judgments. Codebase findings cite specific file:line references; web findings cite URLs. "Should", "best", "better than" are forbidden in research output — those interpretations belong in Design.
Behavioral directives D1-D4 apply — see using-qrspi/SKILL.md → "BEHAVIORAL-DIRECTIVES".
development
Cross-cutting QRSPI reviewer protocol — finding schema, change-type classifier, untrusted-data handling, and dispatch contract. Per-channel emission contracts live in sibling files first-party-emission.md and third-party-emission.md.
development
Use when starting any conversation — establishes the QRSPI pipeline for agentic software development, requiring structured progression through Goals, Questions, Research, Design, Phasing, Structure, Plan, Parallelize, Implement, Integrate, Test, with Replan firing between phases
development
Use when questions.md is approved and the QRSPI pipeline needs objective codebase and web research — dispatches parallel specialist subagents per question, collates per-question findings into research/summary.md
development
Use when goals.md is approved and the QRSPI pipeline needs research questions generated — produces tagged questions that guide the Research step without leaking goals