The audit page reads well and decides badly. Three working prototypes turn the same findings into a table you can clear in a sitting β each takes a different position on where the reasoning goes when the rows get short.
Option B ships, and a click dispatches immediately β the two answers that unblock PR #110. D3βD6 went to the recommendation in each case. The table below records all six. One consequence: the prototypes stage decisions and print the request; the shipped view will not β every β fires a run as it is clicked, and a rule band still sends one request carrying all of its ids.
Not the content β the format. Every finding is a card carrying its own copy of the rule's reasoning, so the page is written for a first read and paid for on every read after that.
Measured in Chrome at 1480 Γ 812 on the deployed page and on Option A with the same 33 findings. The live page also carries 2,883 words and 77 buttons before you have decided anything.
The deeper problem is repetition. Ten of the thirteen rules that fired propose the same change for every finding they produce β eight identical "Assign @jwildfire", three identical "Set board Status to Released". The page asks the question 33 times when there are really 13 questions and a handful of exceptions.
The forks below are about where the why lives. Everything else is settled and identical across the three.
| decide | conf | which issue | title | what changes | kind | |
|---|---|---|---|---|---|---|
| medium | roadmap#17 | Requirement: rebuild safety.agent as a thin overlay⦠| Resolve each open sub-issue: close the finished ones⦠| judgment |
They differ on one question: when a row is 31 pixels tall, where does the reasoning go?
One table for the whole queue, rule bands inside it, and details opening in place under the row they belong to.
The same table, but it never changes shape. The selected row fills a rail on the right β arrow down the list and the reasoning follows you.
The rule is the unit of work. Its reasoning is stated once, the batch decision is the primary button, and the rows underneath exist for exceptions.
Kept for the record. D1 went to B on its own rather than as a toggle on A.
Option A, with B's rail as a toggle rather than a rival. A and B are the same build β the same table, the same bands, the same sidebar β differing only in whether detail renders under the row or beside it. That is a preference, not an architecture, so it should be a control on the page and not a decision made once for you. Default to the rail on a wide screen, because 15 of 33 findings are judgment calls that need a paragraph read before they are decidable, and fall back to inline expansion below 76rem where the rail does not fit.
Take one idea from C immediately. When every finding under a rule proposes the identical change β ten of thirteen rules today β the band should say so once: all 8 Β· Assign @jwildfire. That single line is where most of the remaining reading disappears, and it turns the band's β from a bulk action into an informed one.
Do not ship C first. Its wizard is genuinely faster on a queue like tonight's, but it hides the queue: you cannot see that 13 high-confidence findings are one click away, and a rule you never step to is a rule you never decide. Worth revisiting once the compact view has been lived with for a week β it is a mode, not a replacement.
Asked and answered on 2026-07-25. Every one went to the recommendation.
| # | Question | Decided | Why |
|---|---|---|---|
| D1 | Which view ships on /audit/? | Option B Β· Rail | The table never changes shape and the reasoning follows the selection β the 15 judgment calls are the ones that cost time |
| D2 | Dispatch per click, or stage? | Per click | A decision leaves the browser when it is made; the tray and its payload preview come out. A rule band is still one request, because the payload carries a list of ids |
| D3 | May β at the rule band mute a whole rule? | Yes, confirm above 3 | 1β3 fires straight away; 4 or more names the count and the mute date first. Accept-all never confirms β an accept is visible the next morning, a mute is invisible for 60 days |
| D4 | Where does #109's activity log live? | A fold under the table | Read after deciding, not during, so it never competes with the queue for vertical space |
| D5 | Default sort and grouping | Grouped by rule, worst first | The prototype default, kept |
| D6 | What happens to the long-form view? | Rule reference only | The per-finding cards go; the 22-rule table and the quiet-rules list stay, because an empty audit and a broken one must never look alike |
| D7 | What the page shows between the click and the outcome | Row pill + one run panel | The row reads sending β queued β running β β applied; a panel under the toolbar holds the run link and the outcome re-read from decisions.json β the page reports what the lane recorded, not what the click asked for |
The backend survives intact: repository_dispatch, the re-validation against a fresh audit, the ledger, the run polling. What changes is only the surface calling it: the card list becomes Option Bβs table and rail, the accept and reject buttons move onto the row and the rule band, and the run reporting the PR already built stays as it is (D7). The connect-once token flow is untouched. D2 kept per-click dispatch, so the tray and its payload preview β the one behaviour these prototypes have that the shipped view will not β come out; a rule band sends a single request carrying all of its finding ids, which the lane already accepts.