Generated from cat-harness/skills/authoring/authoring-core/review-heatmap.md — do not edit here.

✎ Edit this page’s source

Review heat map — where to look first

Skill id: review-heatmap · Package: folio-core · Bean: qbfi · Epic: q4jm

The review page (review/ in a folio’s staging preview) opens with a table. It has one row per section, in reading order, and one column per measure. The darker a cell, the more there is. Every cell also shows its number, so colour never carries the meaning alone. A section’s name moves focus to that section in the list of changes below it.

It is not the block-dependency heat map in content-graph. That one draws which blocks depend on which, for a paper’s structure; this one is about a REVIEW.

What each column means, and must not be read as

columncountsfrommust NOT be read as
Changed blocksblocks in the section that the ChangeSet lists: added, removed or changedchangeset.jsonhow much text changed. A one-word edit and a rewrite each count 1.
Open commentsreview comments still open or addressed, with defects counted in bracketsreview-comments.jsonhow bad the section is. One comment may be about the whole section, and a question is not a defect.
Stale commentsopen comments whose block changed AFTER the comment was made (its recorded hash differs from the block’s current one)review-comments.json + blocks.jsonwrong or obsolete. It means re-read the block before replying, because the reviewer saw an earlier version.
Review coverage“3 of 5 reviewed”: the section’s added or changed blocks, and how many have a reviewer VERDICT on their current version. Shaded by what is still unreviewed.review-comments.json’s verdicts + blocks.json (bean px0t)“every comment is resolved”. Resolved comments are not a verdict: a question answered is not a block judged. A verdict on an earlier version is shown on the block and does NOT count, so an edit after review reopens exactly the blocks it touched. A file written before verdicts existed has no verdicts field and reads “no data”, never “0 reviewed”.
QAthe section’s blocks whose latest QA verdicts FAIL (with the worst severity), and those whose verdicts are STALE or that were never auditedblock-qa.json, published by the folio-block-qa-summary Tool after the staging job sweeps the builda pass. A block counts as failing only on a verdict NEWER than the block; an older verdict makes it stale, and stale outranks passing. A section gets a row for QA alone only if something there fails or is stale.

A column with no data says so in every row (“not published”, or “no data” when a build lacks the file). It is never 0 and never blank: zero reads as “measured, and nothing there”, which is exactly what is not known.

Orphaned comments (their block is gone) have no section. They are counted in a last row, “(listed in no section)”, because an open comment is still open.

Where the QA column’s data comes from

The staging workflow first sweeps the build (its qa_sweep input, on by default, bean tw61), then runs the folio-block-qa-summary Tool (cat-harness-tools/scripts/publish-block-qa.ts). The Tool reads each block’s block-qa/v1 verdicts, runs no checker itself, and writes block-qa.json. So the column reports THIS build’s script-checkable criteria. Criteria that need an agent’s judgement are not run by the sweep. Each block is one of:

  • failing: a fresh verdict failed;
  • stale: nothing fresh failed, but some verdict predates the block’s files;
  • passing: every latest verdict is fresh and none failed;
  • unaudited: no verdict at all.

“Passing” says what was judged (bean 9791). Each block also carries needsAgent: its applicable criteria declared automated: false that have no fresh verdict. Which criteria count comes from each criterion’s own declaration, gated as the sweep gates it (applies_to, the folio’s active voices). The column then reads either:

  • “N passing on scripts only (M criteria need an agent)”; or
  • “passing, every applicable criterion judged”.

A summary published before this field existed reads “passing (this build does not say whether agent-judged criteria were run)”, never “all judged”. A verdict never given is not a pass, the same rule as stale-versus-passing one level up.

Freshness is the QA sweep’s own rule, including the uses-graph hash that graph-scoped criteria depend on. Leaving that hash out made every detangler criterion read stale straight after a sweep.

The QA sweep writes verdicts under the instance root (fixed by bean s3p2, 2026-09-23). Before that fix, it wrote them under the directory it was run on, so the summary still reads there second, for folios swept before the fix.

How the colour was chosen

This follows the dataviz skill:

  • Scale. One hue (blue), sequential, in three ordinal steps. Each column is scaled to its own maximum, by thirds; zero has no fill.
  • Light theme: steps 250 / 400 / 550.
  • Dark theme: steps 600 / 500 / 400, chosen for the dark surface rather than flipped from the light ones.
  • Validation. Both ramps pass validate_palette.js --ordinal: they are monotone, their steps are visibly apart, and the lightest clears 2:1 against the surface.
  • Ink. Every cell’s text colour clears 4.7:1 against its fill.

The table is a real <table> with row and column headers, so it is its own table view for a screen reader. Every cell also has a hover title saying what it counts.

Where it lives

  • cat-harness-tools/scripts/review-heat.ts: computeHeat (the numbers), heatBucket (the thirds) and renderHeat (the table). The page embeds all three with toString(), so the tested functions are the ones that run.
  • blocks.json carries each block’s section, so a comment on an UNCHANGED block still lands in its section’s row.

Adding a column

  1. Say what it counts and what it must not be read as, in the table above, before writing code.
  2. Its data must be published in the preview, never read from an agent’s /tmp.
  3. Add it to computeHeat and renderHeat, with a test for its “no data” state as well as its numbers.

Processes that run this skill

processstep(s) that name it
Content Change and ReviewSlice the change and assign reviewers

folio-assistant — code under the Apache License 2.0, documentation under CC BY 3.0. Generated schema and API references are rebuilt from source on every push to main.

deployed dev