Academyby Dasow

Stop 6 of 10 · Daily

Findings to tickets

The one write the studio's tools are allowed: a ticket on the studio board, behind an allowlist, a dry run by default, an approval step and an append-only log.

Watch first · 1:01

Nine checks, forty sites, one queue

The first full night produced two hundred and six findings. Dany read eleven of them. A queue nobody reads is worse than no queue, because it looks like coverage.

Two rules cut it to something Dany and Mo actually work from. Severity 1 and 2 become tickets on the studio board. Severity 3 and 4 stay in the database and appear in one weekly digest. And a finding that has been seen before is an update to its ticket, never a second one.

Severity Example Where it goes
1 Site down, TLS expiring inside fourteen days Ticket, same morning
2 Key page returning 5xx, contact page missing its form Ticket
3 Slow page, missing canonical, broken internal link Weekly digest
4 Cosmetic, informational, first sighting of anything new Database only

The fingerprint

site_id, check name and the detail with numbers and dates stripped out, hashed. That triple is the identity of a problem. Same fingerprint and an open ticket means increment the seen count and update the timestamp. Same fingerprint and a closed ticket means reopen it and say how long it stayed fixed.

The guarded write

This is the only place in the whole repository that sends a request to something the studio does not own the file for.

import { guard } from '../lib/guard.mjs';

export function fileFinding(finding, { apply = false } = {}) {
  return guard({
    action: 'board.create_ticket',
    target: `${BOARD_HOST}/projects/${STUDIO_PROJECT_ID}/tickets`,
    payload: ticketFrom(finding),
    apply
  });
}

Four things happen inside guard, and stop 8 builds it. The action is checked against an allowlist of exactly one entry. The target is checked against one host and one project id. With apply absent or false the call is a dry run that returns the payload and sends nothing. And the attempt is written to an append-only log before the request goes out, so a request that fails halfway still left a record.

The tool holds no client credential. The only token it reads is the studio's own board token, from the file outside the tree.

The ticket body, from rows only
Here is one finding row and the four check rows behind it: [paste the finding row and the check rows].

Write the ticket body. Title in under twelve words naming the client and the symptom. Then the evidence as a short list, every line traceable to one of the rows I gave you, with the row ids. Then the owner: studio, host or client. Then the one next action.

Do not estimate impact, traffic or lost enquiries. If you want to say something is urgent, say which measured fact makes it urgent. If a field in the finding is empty, write unknown rather than filling it.
Build the fingerprint and prove it dedupes
Write the fingerprint function for my findings: site id, check name, and the detail string with all numbers, dates and times removed, hashed to a short hex string.

Then a node --test file that feeds it the same fault on four consecutive nights with different timestamps and different response times, and asserts one fingerprint. Then feeds it the same check name on a different page of the same site and asserts a different one. Show me the two detail strings that worry you most, where my rule either merges two real problems or splits one.

Quick check

Try it

Report a bug or share feedback