← Guide

Reviewing & triaging blockers

The coordinator's triage job — confirm or reject a suggestion, record who's responsible, resolve and archive, acknowledge a disputed claim, and read the lost-time ledger. Plus the QS's commercial-author role.

Try it: the Blocker awaiting triageTry it ↗ scenario seeds a fresh Demo World with a crew stood down waiting on a permit and a suggested blocker sitting in the triage queue, so you can walk the confirm decision below against real data.

A Blocker is the site's only record of Lost time, and triage is where a suggestion becomes a counted blocker. This page is for the two commercial-band roles who work that record: the coordinator (who adjudicates triage) and the QS / commercial user (who authors and reads the record but does not triage).

For Coordinator / triage band

Your role

You are the triage gate for the site's lost-time record. Field crews and HSE suggest blockers; a coordinator (or site manager, or admin) decides whether each suggestion is real. When you confirm one it becomes a live, site-wide, counted blocker; when you reject it, it drops off every active surface as audit trail. You also record who is responsible at confirm — the single value the lost-time rollup attributes blame by — and you resolve and archive blockers as work moves again. You hold the full commercial band (blocker_triage on top of blocker_manage / blocker_edit / blocker_suggest) and you can read Lost time (lost_time_view).

What you can and can't do

You can
  • Confirm a suggested blocker → confirmed (blocker_triage) — POST .../confirm. The decision propagates across the whole declaration, so a close-time split does not make you adjudicate the same claim three times.
  • Reject a record → rejected (terminal; reason required) — POST .../reject. Admits a confirmed record as well as a suggested one: withdrawing a figure already counted is a licensed correction.
  • Record / correct who is responsible on a confirmed blocker — POST .../responsible — at any lifecycle state, a closed one included.
  • Complete the cause link on a cold knock-on raise — "link the causing record", the blocker_triage band's own completer, because you are the first reader who reliably holds both records.
  • Declare a blocker directly and edit any in-scope blocker's window, counts, note and affected work.
  • Resolve / close a blocker (POST .../resolve) and archive a resolved one (POST .../archive).
  • Acknowledge or dispute a blocker as a counter-signal (POST .../acknowledge) — without changing its status — and chase a still-running record.
  • Read the lost-time ledger — the two-tier crew-hours rollup.
You can't
  • Un-reject or re-open. There is no reopen edge: a rejected (or resolved) situation that recurs is a fresh raise, naming what it re-raises.
  • Reject without saying why. A reason-less reject is refused (422 blocker_reject_reason_required) — the reason rides the raiser's notification and the raise this again affordance, and it is what structurally precludes bulk rejection.
  • Silently change who lost the time. The loser is derived from the blocker's own contractor; you set the responsible party, not the loser.
  • Contest an attribution. That verb belongs to the accused firm's own members, not to you — you dispute the figure, they contest the blame.

Note: Confirm and reject are the coordinator band's verbs, not the QS's. The QS declares, edits, resolves and archives, but a suggestion is adjudicated only by blocker_triage holders (coordinator / site manager / admin). If a QS tries to confirm, the service returns 403. Because self-confirmation at birth also rides that band, a QS's own declare lands in your queue too.


Your tasks

Task 1 — Confirm or reject a suggestion

This is your core job. Two ways in: a task from My Tasks, or the Blockers ledger on the Commercial surface's Completions drill-in.

Via My Tasks (the usual route):

  1. When anyone suggests a blocker, you receive a confirm_blocker task labelled "Review suggestion" in the My Tasks panel (T), plus an in-app (and, where email is configured, an emailed) notification.
  2. Click the card. It deep-links straight into the confirm modal, focused on the oldest undecided member of that declaration. (The card is a pure deep link — it carries no action of its own, and it clears only when nothing on that declaration is left undecided, not on any single confirm, reject or close.)

Via the Blockers ledger:

  1. Open the Commercial surface — dock key I — and pick the Completions tile. Click the Blockers tab.
  2. In the Suggested section each row carries a pending triage badge and a Review… button. Click Review… to open the same confirm modal.

In the confirm modal (a pre-filled declare form, not a bare approve button):

  1. Read the suggestion: its cause, the "what's in the way?" note and any photo, the actuals window (work stopped atwork resumed at), the gang and send-home counts, and the affected work the raiser named.
  2. Correct anything. Every field is editable at confirm — fix the window, adjust the counts, add or remove affected work, tidy the note. What lands is what you confirm, not what was suggested.
  3. Answer who is responsible (Task 2, below). The select must be answered, not merely left alone: omitting it refuses 422 blocker_responsible_required, and "Nobody — no firm at fault" is a first-class answer.
  4. Choose your decision:
    • ConfirmPOST .../confirm. The blocker moves suggestedconfirmed, goes site-wide, and its figures move from the awaiting-triage tier into the confirmed one. Everyone on site gets an in-app notice; the involved firms are emailed; the firm you named responsible is told it has been named.
    • Reject → open Reject…, type the reason in "Why is this not a blocker?", and RejectPOST .../reject. The reason is required. The record moves to rejected and its lifecycle flips to resolved, so it leaves every active surface and its figures leave the rollup. The raiser is notified with your reason in the message; if you rejected an already-confirmed record, the firm it blamed is told the attribution is withdrawn.

Note: A suggested blocker emits no attribution — its rows read pending, and the awaiting-triage tier has no by-responsible axis at all — so the blame numbers a QS reads never flicker on an unvetted grievance. Its crew-hours, however, are already in the rollup: silence is not a decision, and a total that only grew when you got round to the queue would be its own wrong number.

A suggestion (and a rejected one) is nonetheless withheld from the site at large. Four readers hold it: its raiser; the curation and proxy bands (blocker_manage / blocker_edit); HSE, through hse_register_manage — the arm that exists so the injury register's cross-firm raise resolves for her; and any member of the firm whose work stopped, a verb-less read that runs at every triage status, rejected included. What a suggestion is not is site-wide: the confirmed tier's D-2 read and the accused firm's read both start at confirmed, so the subject of an unvetted accusation is never told. Anyone outside those arms gets a plain 404, so a possibly cross-trade grievance never leaks before you've vetted it.

Task 1b — Run the coordination meeting from the table

The coordination meeting is this tab, in meeting mode — there is no meeting surface, no "meeting held" stamp and no attendance record anywhere.

  1. On the Blockers tab, press Meeting mode. The tab re-reads itself as the day's two bands and shows the day it is cut on.
  2. Band one — Awaiting triage, every open raise. Every row still awaiting a decision, however old, closed-but-suggested included: silence is not a decision — a crew closing its own window records a fact, triage vets a claim.
  3. Band two — Decided in this report's day. Everything raised, confirmed or rejected inside the daily report's own site-local day. "Since the last meeting" resolves to that window, which is exactly why nothing is stamped.
  4. Both bands are grouped by firm, because the room works one firm at a time. A raise landing mid-sitting appears at the end of its firm's group and nothing re-sorts under the projector; a row you decide keeps its place with a decided · confirmed / rejected mark and loses its verbs, banding on the next open.
  5. Work the row in place. Review… expands the row into the same triage form the confirm modal shows — the whole form, so a confirm is still an answered question and a reject still carries its required reason. One row is open at a time. Close collapses it.
  6. The count is the firm's word. Inside the expansion the completion fields (gang, send-home, basis refs) are open on that firm's own row — and otherwise the question that would license them stands in their place: Present for ⟨firm⟩? Name the representative in the group header — pick a member, or type the name of somebody with no login — and the fields open. The count then records who spoke it: their name, their firm and the meeting's date land on the count's own timeline event, and the basis bundle reads it back as "spoken by ⟨rep⟩, ⟨firm⟩, at the ⟨date⟩ meeting". The answer is per sitting: it is not stored, and closing the mode forgets it.
  7. The thread is the rebuttal. The discussion thread hangs under the expanded row and is the only place an argument goes — there is no rebuttal field and no triage-note box. A firm's representative with a login writes their own; the coordinator quotes one who has not. A row somebody has argued says so on its collapsed face with a comment count.
  8. Chase a count-less row inline: one tap, one timeline row, no notification — it is a disclosure about silence, never a figure.

Note: The count line on a meeting row reads the send-home count with its crew-hours where the firm has spoken, and "no count · ⟨firm⟩ to say" with the chase state where it has not. A dash is never a zero, and there is no money on the meeting table — £ lives on the Lost time ledger.

A row somebody messaged in rather than saw carries a quiet tell on its collapsed face — relayed · WhatsApp — wherever the record names a channel. A first-hand raise says nothing, which is what every phone raise is; the record's own face carries the whole as told to us triple. Treat the tell as a reason to ask the firm's representative in the room, not as a reason to discount the row: a count in a forwarded message is prose, and only that firm can speak it.

Nothing on the table is assigned to a person. A blocker names the firm whose site team reported it, and what closes the "assignment" is the meeting itself: the row is on the table and that firm's supervisor is in the room.

Task 1c — The doors into the meeting

Every road that counts untriaged raises leads to this table, and nothing else shows them as rows:

  1. The Noticeboard's awaiting-triage line. "3 awaiting triage · oldest 8 days" is a count and a door — tap it and the Blockers tab opens in meeting mode. The Noticeboard itself never lists a suggestion; that is what this table is for.
  2. The daily report's Blockers section. In the report rail, Open the meeting table on the section header opens the table whole, and the ↗ beside a printed row opens it on that record. When you leave the table — one Escape, or the header's ✕ — the report panel comes back on the same draft: the session is saved on the server, so nothing you had typed is lost, and the section's rows carry the meeting's decisions back in.
  3. The dock, as always. Commercial ▸ Completions ▸ Blockers, then Meeting mode.

Each door needs the triage grant. A reader who cannot triage sees the section and the line, and is offered no door that opens on nothing.

What the printed sheet says. The report prints the confirmed rows and one line beneath them — "N raises awaiting triage, not listed". Unvetted figures never reach paper, and nothing vanishes without a count; the weekly carries the same line on both variants, and an evidence pack inherits it with the rest of its frozen context. If a figure has to print, confirm it at the table first — which is the whole point of the sitting.

Task 2 — Record who is responsible (at confirm, or later)

Blame is a commercial claim, and it is recorded only by the triage band — at confirm, or afterwards on a confirmed blocker via set-responsible — never off a raw suggestion. (A direct declaration also carries blame from birth, because declaring is itself a commercial-band act; but setting blame on a suggestion is a triage verb, not a QS one.)

  1. In the confirm modal, the Responsible party control opens unanswered — nothing is ever pre-selected. It renders up to two offers as labelled options: the raiser's tag, wherever the raise named a firm, and a machine derivation, which only a Dependency violation cause feeds (it walks the violation episode's edge to the upstream/predecessor trade; every other cause derives nothing). Pre-selecting either would make accepting an unvetted accusation the path of least resistance, so the select refuses to guess.
  2. Accept, override, or clear it. Only the value you accept is written to responsible_contractor_id — the one field the lost-time rollup attributes blame by.
  3. To correct blame on an already-confirmed blocker, open it and use Set responsiblePOST .../responsible (blocker_triage; the record must be confirmed, but any lifecycle state is fine — a closed one included. A coordinator who learns on Friday who caused Tuesday's stoppage must be able to say so).

Note: A field user's "Whose stuff?" tag is a hint only — it is never read by the rollup and becomes blame solely when you accept it here. Clearing responsible entirely is a legitimate decision ("nobody's fault"): the loss still counts against the loser, but under Unattributed on the blame axis. Whichever way you answer, the record stamps how — typed, the raiser's tag accepted, the machine suggestion accepted, a later correction, or the explicit "nobody" — as a lens, never a weight.

A re-decision is not silent: it notifies the record's own firm, the firm now named, and the firm named before, so nobody is left believing they are still carrying a loss that moved.

Task 3 — Close a blocker when work moves again

  1. Open the blocker (the Ledger section of the Blockers tab, or its pin) and choose ResolvePOST .../resolve, the inline lifecycle verb: active → resolved, with an optional work_resumed_at that records the restart in the same gesture.
  2. From the record's own detail surface (and from the still-running chase list) the same act runs through the close family instead — close/preview first, which asks what closing at that instant would do and stores nothing, then close, which lands the plain close, the "nothing to declare" branch, an accepted or declined split, and the close-and-raise, all in one transaction.
  3. Set work resumed at to when the crew actually got going — this closes the loss window. (Leave it open while the record is still open and it reads as still stopped, its age ticking against now — an age, not a cost: nothing is counted until work restarts.)

Note: Closing is not the same as saying work resumed — resolved_at and work_resumed_at are separate stamps. The loss window is the work window; closing the record just moves it off the active pile. Triage state is not a precondition: a still-suggested record closes exactly like a confirmed one, and only a rejected one refuses. Closing launders nothing — a closed-but-suggested record's figures stay in the awaiting tier and it stays rejectable. Reach is the commercial band for anything in scope plus any member of the record's own firm: the restart is a firm fact, not a personal one.

Because the two stamps are separate, a record closed without a resumption time is a third thing: not still stopped, but with no measurable window either. It shows no restart recorded, books no crew-hours, and is left out of the totals with the omission counted beside them — the system will not guess a restart it was never told about. Set the resumption time on the record and it starts counting.

Task 4 — Read the lost-time ledger

  1. Open the Commercial surface — dock key I — and pick the Lost time tile (lost_time_view; the header reads Site-wide).
  2. Read the two tiers, stacked and never fused: confirmed (carrying four axes — by loser, by responsible, by cause, by place) and awaiting triage (the loser axis only, because nobody has been named responsible yet, and no money). They are objects of different shape precisely so that no row, column or of-which clause can express a sum across them.
  3. Each row shows the window, the stood-down count and the derived crew-hours (window × stood-down). Still-stopped rows show a running age and count towards nothing until they resume — a stoppage that has not finished has no measured duration; the Still running section lists them, spanning both tiers, and live_count beside the totals says how many. Rows marked no restart recorded show a dash rather than a zero and are disclosed by undeclared_count in the same way.
  4. Use the review-range pill (7 / 14 / 30 days) to bound the totals. This pill is surface-local — it never moves the map scrubber.

Note: A range decides membership, never quantum. Nothing is clipped inside a record: a stoppage whose window overlaps the review range contributes its whole figure, and it carries a "crosses ⟨date⟩ · counted whole" chip so you can check that claim on its face. Row and totals therefore agree — pro-rating a window would be never-apportion in a different hat, and it was removed for exactly that reason.

The surface also prints its own predicate"triage_status IN (confirmed, suggested) AND deleted_at IS NULL" — so the next reader never has to assume a rejected row is merely hidden.

Task 5 — Acknowledge, archive, or curate a mis-declared blocker

  • Acknowledge / disputePOST .../acknowledge records your counter-signal, on the figure, without changing status. A disputed blocker still counts if it's confirmed — the dispute is a flag for review, not an off-switch. Its symmetric partner, contested, is the accused firm's counter-signal on the attribution, and it is deliberately not yours: it is row-scoped to members of the firm named responsible, who hold no blocker band at all. Both are arithmetically inert lenses.
  • Chase a still-running record — a dated management gesture, kin to acknowledge, that appends a timeline event, moves no status and mints no notification. Its state reads back through the ledger's chase line, never as a figure.
  • Archive a resolved blocker — POST .../archive (blocker_manage) — to clear it from the working ledger once it's history.
  • Soft-delete a genuinely mis-declared blocker — DELETE .../{blocker_id} — the reversible mistake path (restore with POST .../restore). Reject is for "not a blocker"; delete is for "this record shouldn't exist."

What you'll be notified about

Trigger You get Where it lands
A blocker is suggested In-app + email (where configured) + a confirm_blocker task My Tasks card "Review suggestion" → confirm modal
A blocker is confirmed (by anyone) Site-wide in-app notice Notification bell / noticeboard Blockers section
A confirmed record you triaged is corrected In-app notice naming the field and the actor's firm Notification bell
A blocker's affected-work set changes In-app notice (if your firm is in the new set) Notification bell
A cause is re-typed off hazard In-app notice with the from→to values Notification bell

You receive the confirm_blocker task on every raise that is born suggested — which now includes a QS's direct declare and any cross-firm declare, because self-confirmation rides the triage band. The task does not clear on a single confirm, reject or close: it is disposed only when nothing on that whole declaration is left undecided.

A retroactive correction is no longer silent

A confirmed record's window, counts, basis, evidence, extent or cause emits blocker_updated / blocker_cause_changed, and a blame re-decision emits its own event; all of them ping every written row's confirmer, the record's own firm and any firm named responsible (plus the firm named before, on a re-decision). What stays quiet by design is contest, chase and the cause link.

Gotchas

  • There is no reopen edge. Reject and resolve are one-way. A recurrence is a fresh raise carrying re_raise_of, with a fresh clock — the same discipline snags and permits use. Don't hunt for an "un-reject" button; there isn't one. At most one live re-raise per predecessor.
  • Reject vs delete. Reject = "this isn't a blocker" (audit trail, raiser notified with your reason). Soft-delete = "this record is a mistake" (reversible, no notification). Use the right one; they read differently to an auditor.
  • The QS can't confirm or reject. If a QS says a suggestion is "stuck", it's because triage is your band, not theirs — and that now includes the QS's own declares, which enter your queue rather than self-confirming.
  • The queue is declaration-grain, not row-grain. A close-time split turns one declared loss into several records; you adjudicate the claim once and the decision propagates. An extension follow-on is different — it asserts new loss, so it is its own queue item and triages afresh.
  • An untriaged record is already counted. Leaving the queue does not park the figures — it parks them in the awaiting-triage tier, in plain view, with the oldest latency shown in days. The tier exists to make inaction visible, not to hide it.

For QS / commercial

Your role

You own the commercial record but you do not adjudicate triage. You can declare blockers directly — though a declare of yours enters the coordinator's queue like any other raise, because self-confirmation at birth rides blocker_triage and you do not hold it — edit any in-scope blocker's substance — the window, the stood-down headcount, the note, the affected work — link a snag cause, resolve and archive, acknowledge/dispute, and read the lost-time ledger. What you can't do is confirm, reject, or set who's responsible on someone else's suggestion — those are the coordinator band's (blocker_triage, which you don't hold). You hold blocker_manage, blocker_edit, blocker_suggest and lost_time_view.

What you can and can't do

You can
  • Declare a blocker directly → POST .../blockers. It enters suggested and mints the coordinator's triage task: the door admits you, but only a blocker_triage holder's own-firm declare self-confirms.
  • Edit the window, counts, note, extent and cause of any in-scope blocker → POST .../update. This is not silent: it pings the record's confirmers, its own firm and any firm named responsible.
  • Set the affected work — replace the whole set of affected permits / entities / contractors / whole-site → POST .../affected.
  • Link a Snag as the cause (the commercial-band-only claims instrument — see Snags & work close-out).
  • Resolve, archive, acknowledge/dispute, and soft-delete / restore.
  • Read the lost-time ledger — by loser and by responsible party.
You can't
  • Confirm or reject a suggestion, or set the responsible partyblocker_triage, coordinator band only. A suggestion sits in the coordinator's queue, not yours.
  • See a suggestion you didn't raise until it's confirmed? — no: you do see suggestions, because you hold blocker_manage (the commercial band is the private audience). You just can't triage them.

Your tasks

  1. Declare a stoppage you already know is real — from the Add menu (A then B, which arms the map for the click that anchors it), or from an incident / observation / delivery pin's Declare blocker action, or by turning a red clash into a blocker. See Raising a blocker. It lands suggested for the coordinator to adjudicate — but its crew-hours are in the ledger's awaiting tier immediately, so nothing waits on the queue to be visible.
  2. Keep the lost-time record honest — edit the window and the send-home count as the actuals firm up (this is the substance of the crew-hours number), and set the affected work so the right firms are on the notification and the map paint.
  3. Attribute through the cause, not by hand — where a stoppage stems from another trade's Snag, link it as the cause so the record carries the claim. (Blame — responsible_contractor_id — is still the coordinator's to accept at triage.)
  4. Read the ledger — Commercial ILost time. This is your primary surface; the crew-hours totals by loser and by responsible party are what the commercial conversation runs on.

What you'll be notified about

You are not in the triage audiences — the confirm_blocker task and the suggested / confirm / reject pings flow to the coordinator band, not to you. But you are in the site-wide audience: like every role, you get the in-app "blocker declared" notice on each confirmed blocker, plus an affected-set change if your firm is named. You also hear when a confirmed record you triaged, own or are blamed on is corrected, and when a standing rate re-prices records already printed — that ping goes to the whole lost_time_view band and never to the firm being priced.

Gotchas

  • You author the record; the coordinator adjudicates the queue. That split is deliberate: the commercial owner and the triage arbiter are different hands.
  • A snag cause is a pointer, not a leak. Linking a snag exposes only the snag's label on the blocker; the snag body stays behind its own commercial-band visibility. Only the blocker side can author the link.
  • Lost time counts blockers only. Snags show as zero-hour responsiveness rows in the same ledger. Don't read a busy snag list as lost time — the cost, if any, shows through the blocker a snag caused.

See also: Blockers & delays overview · Raising a blocker · Snags & work close-out · Reference.

Blockers guide: Overview · Reviewing & triaging · Raising · Snags & close-out · Reference

Was this page useful? Report a problem

No cookies and no third-party analytics. A verdict records this page's path — and a search that finds nothing records the words you typed — in this site's own server log.

Generated from source · SimOops living system reference