Multi-lane report assembly
Assemble ONE evidence-graded record (or report) from several parallel lane
outputs — the standard shape when you fan out research/review lanes and
integrate their findings yourself. The lanes produce finding blocks; you lift
them verbatim, consolidate, renumber, and gate the result.
When this fires
- You dispatched 2+ lanes that each returned
### F# — <claim> [GRADE] blocks
(evidence-first shape) and you must merge them into a single record.
- You are renumbering or re-sectioning findings from multiple sources into one
deliverable that a strict renderer/checker will parse.
Lane output contract (demand this from lanes)
- One
### F<n> — <claim, present tense> [GRADE] block per finding; grade in
the closed set {MEASURED, READ, INFERRED, UNVERIFIED} at the END of the claim.
**Evidence:** line REQUIRED for READ/MEASURED (path:line or URL).
- INFERRED states its reasoning basis; UNVERIFIED states why not checked.
- A
## Still open list and a grade-mix line (N findings: x READ, ...).
- Findings carry
Type: (FLAW/GAP/ACCEPTED/INFO) + severity (L×I) when scored.
Getting the full lane reports (Hermes)
The consolidated batch message may arrive late, and the LIVE delegation transcripts
(~/.hermes/cache/delegation/live/<delegation-id>/task-N.log) ABBREVIATE long summaries —
the final line ends in …(+N chars) and is NOT the full report. Do not merge from the
transcripts; you would lift truncated claims.
The authoritative full summaries live in the Hermes state DB (read-only):
sqlite3 "file:$HOME/.hermes/state.db?mode=ro" \
"SELECT result_json FROM async_delegations WHERE delegation_id='<id>'"
result_json → results[], each carrying summary (may be truncated), summary_full_path
(the full markdown, e.g. ~/.hermes/cache/delegation/subagent-summary-N-<ts>.txt), plus
model, api_calls, and tokens {input, output}. The live-dir manifest.json holds only
paths and status. To record lane tokens in the task tracker without manual counting:
task_tracker.py subagent <taskId> --delegation <delegation-id> --description "..." reads the
same row. Use the summary_full_path files as the verbatim lift source for assembly.
Assembly steps
- Extract blocks with
^### (F\d+[ab]?) — (MULTILINE). The id may contain
letters (F4b parses); the claim line must end with the grade in brackets.
- TRUNCATE every block at the first
## header. Lanes embed their own
## Still open + grade-mix sections at the end of their file — lifted
verbatim, that header lands INSIDE the last finding's body and ends the
renderer's ## Findings capture early. Symptom: the provenance chart counts
only the first section's findings (e.g. 13 of 41) while the markdown looks
complete. Strip at body.find("\n## Still open") and rstrip separators.
- Dedupe cross-cutting themes. When two or three lanes independently file
the same gap (rotation cadence, missing diagnostics, shared-key auth),
consolidate into ONE finding in a dedicated cross-cutting section, with an
italic provenance note naming the source lane findings. Never keep both a
lane finding and a consolidated twin.
- ACCEPTED items go to a register section only (never scored, never in the
scored sections). Each entry keeps decision citation + residual risk +
revisit trigger.
- Renumber sequentially, then run a stale-cross-ref pass. Renumbering
breaks every in-body reference ("see F12", "(F5)", "F2's ..."). Grep the
assembled file for every old id pattern and map each to the new id or the
register id (E#). A reviewer WILL find these — do the pass before review,
not after. This is the most common quality-gate finding on assembled
records.
- Section structure that renderers accept: all
### F# blocks under one
## Findings; #### subheaders for clusters are fine; front sections
(## Executive summary, ## Scope & method) and trailing sections
(## Still open, ## Verification checklist) must NOT appear between
finding blocks. State grade mix + severity counts in the exec summary;
## Still open non-empty.
- Render as the format gate. A clean render is a real check: the renderer
refuses ungraded claims, READ/MEASURED without Evidence lines, and any HTML
target inside the repo. Render to a temp dir; never commit the HTML.
Verification checklist
Wave-PR delivery (sequential wave branches under squash merges)
When the work ships as one PR per wave and merges are squash merges, see
references/wave-pr-hygiene.md — branch rebasing, draft-gating on owner-side
prerequisites, and the gh CLI quirks that look like failures but aren't.
Gotchas
- Trust the renderer's count, not the markdown. A truncated capture still
renders "fine" for the part it saw. Check the provenance chart's total.
- Consolidation ≠ summarization. Merge by quoting the lane evidence lines,
not by rewriting the claim. The consolidated finding must cite what each
source lane evidenced.
- Renumbering is not a mechanical sed. In-body references are prose
("the F5-chain", "F2's zero diagnostic settings") — a plain id-replace pass
misses the prose forms. Grep for the ids with context, then read each hit.
- Register ids (E#) are cross-referenced too. Findings reference accepted
items; those refs also break under renumbering.
1---2name: multi-lane-report-assembly3description: Use when assembling outputs from 2+ parallel research/review lanes into one evidence-graded record: lift finding blocks verbatim from the authoritative full summaries (never the truncated delegation transcripts), enforce the lane contract (### F# — claim [GRADE], Evidence line), truncate at embedded '## Still open' headers, renumber, and gate the result.4license: MIT5---67# Multi-lane report assembly89Assemble ONE evidence-graded record (or report) from several parallel lane10outputs — the standard shape when you fan out research/review lanes and11integrate their findings yourself. The lanes produce finding blocks; you lift12them verbatim, consolidate, renumber, and gate the result.1314## When this fires1516- You dispatched 2+ lanes that each returned `### F# — <claim> [GRADE]` blocks17 (evidence-first shape) and you must merge them into a single record.18- You are renumbering or re-sectioning findings from multiple sources into one19 deliverable that a strict renderer/checker will parse.2021## Lane output contract (demand this from lanes)2223- One `### F<n> — <claim, present tense> [GRADE]` block per finding; grade in24 the closed set {MEASURED, READ, INFERRED, UNVERIFIED} at the END of the claim.25- `**Evidence:**` line REQUIRED for READ/MEASURED (path:line or URL).26- INFERRED states its reasoning basis; UNVERIFIED states why not checked.27- A `## Still open` list and a grade-mix line (`N findings: x READ, ...`).28- Findings carry `Type:` (FLAW/GAP/ACCEPTED/INFO) + severity (L×I) when scored.2930## Getting the full lane reports (Hermes)3132The consolidated batch message may arrive late, and the LIVE delegation transcripts33(`~/.hermes/cache/delegation/live/<delegation-id>/task-N.log`) ABBREVIATE long summaries —34the final line ends in `…(+N chars)` and is NOT the full report. Do not merge from the35transcripts; you would lift truncated claims.3637The authoritative full summaries live in the Hermes state DB (read-only):3839```bash40sqlite3 "file:$HOME/.hermes/state.db?mode=ro" \41 "SELECT result_json FROM async_delegations WHERE delegation_id='<id>'"42```4344`result_json` → `results[]`, each carrying `summary` (may be truncated), `summary_full_path`45(the full markdown, e.g. `~/.hermes/cache/delegation/subagent-summary-N-<ts>.txt`), plus46`model`, `api_calls`, and `tokens {input, output}`. The live-dir `manifest.json` holds only47paths and status. To record lane tokens in the task tracker without manual counting:48`task_tracker.py subagent <taskId> --delegation <delegation-id> --description "..."` reads the49same row. Use the `summary_full_path` files as the verbatim lift source for assembly.5051## Assembly steps52531. **Extract blocks** with `^### (F\d+[ab]?) — ` (MULTILINE). The id may contain54 letters (`F4b` parses); the claim line must end with the grade in brackets.552. **TRUNCATE every block at the first `## ` header.** Lanes embed their own56 `## Still open` + grade-mix sections at the end of their file — lifted57 verbatim, that header lands INSIDE the last finding's body and ends the58 renderer's `## Findings` capture early. Symptom: the provenance chart counts59 only the first section's findings (e.g. 13 of 41) while the markdown looks60 complete. Strip at `body.find("\n## Still open")` and rstrip separators.613. **Dedupe cross-cutting themes.** When two or three lanes independently file62 the same gap (rotation cadence, missing diagnostics, shared-key auth),63 consolidate into ONE finding in a dedicated cross-cutting section, with an64 italic provenance note naming the source lane findings. Never keep both a65 lane finding and a consolidated twin.664. **ACCEPTED items go to a register section only** (never scored, never in the67 scored sections). Each entry keeps decision citation + residual risk +68 revisit trigger.695. **Renumber sequentially, then run a stale-cross-ref pass.** Renumbering70 breaks every in-body reference ("see F12", "(F5)", "F2's ..."). Grep the71 assembled file for every old id pattern and map each to the new id or the72 register id (E#). A reviewer WILL find these — do the pass before review,73 not after. This is the most common quality-gate finding on assembled74 records.756. **Section structure that renderers accept:** all `### F#` blocks under one76 `## Findings`; `####` subheaders for clusters are fine; front sections77 (`## Executive summary`, `## Scope & method`) and trailing sections78 (`## Still open`, `## Verification checklist`) must NOT appear between79 finding blocks. State grade mix + severity counts in the exec summary;80 `## Still open` non-empty.817. **Render as the format gate.** A clean render is a real check: the renderer82 refuses ungraded claims, READ/MEASURED without Evidence lines, and any HTML83 target inside the repo. Render to a temp dir; never commit the HTML.8485## Verification checklist8687- [ ] No `## ` header inside any finding body (grep for `^## ` between `### F` blocks)88- [ ] Old-id grep pass clean (every "see F#/E#" resolves in the final numbering)89- [ ] Every READ/MEASURED block has `**Evidence:**`90- [ ] Grade mix + severity counts in exec summary match the rendered chart91- [ ] Renderer ran clean to a path OUTSIDE the repo92- [ ] `## Still open` non-empty, or its emptiness defended9394## Wave-PR delivery (sequential wave branches under squash merges)9596When the work ships as one PR per wave and merges are squash merges, see97`references/wave-pr-hygiene.md` — branch rebasing, draft-gating on owner-side98prerequisites, and the gh CLI quirks that look like failures but aren't.99100## Gotchas101- **Trust the renderer's count, not the markdown.** A truncated capture still102 renders "fine" for the part it saw. Check the provenance chart's total.103- **Consolidation ≠ summarization.** Merge by quoting the lane evidence lines,104 not by rewriting the claim. The consolidated finding must cite what each105 source lane evidenced.106- **Renumbering is not a mechanical sed.** In-body references are prose107 ("the F5-chain", "F2's zero diagnostic settings") — a plain id-replace pass108 misses the prose forms. Grep for the ids with context, then read each hit.109- **Register ids (E#) are cross-referenced too.** Findings reference accepted110 items; those refs also break under renumbering.