Blockers & delays
What a blocker is (and what it isn't), the suggest→confirm triage model, who can do what, the three ways one gets raised, and where blockers surface.
A Blocker is SimOops' record that something stopped or impaired specific work over an actual window of time — the access road the council closed, the scaffold that wasn't struck, the delivery that never came. It is the site's single source of truth for lost time, so it sits on the commercial axis: the QS and coordination team own it, and it never gets created automatically. This page is for site coordinators and QS users who confirm, reject, and read blockers.
Blocker vs snag vs delay — the words matter
Three nearby concepts are deliberately kept apart, because conflating them is how sites lose track of who owes whom time.
| Term | What it is | Who raises it | Feeds lost time? |
|---|---|---|---|
| Blocker | A timed work stoppage or impairment — the sole canonical record of "work couldn't proceed, here's the window", however it arose. | Anyone on site suggests; the commercial band declares / confirms. | Yes — blockers are the only thing lost time counts. |
| Snag | An own-work defect — work your own team built that isn't to spec, flagged while recording completion. A snag can never be raised against another trade. | The team that built the work, on its completion record (no standalone raise button). | No — snag clocks are responsiveness metrics only. |
| delay | The planning concept: a declared work-line dependency that has been contradicted (internally a Dependency violation). A delay is a cause; it doesn't hold a stoppage window itself. | Surfaces automatically from the dependency graph; a human then declares the blocker. | Only once it creates a blocker. |
The rule of thumb: a cross-trade grievance is a blocker, not a snag. A snag is you flagging your own not-quite-finished work; the moment one trade's problem stops another trade, that's a blocker. And a delay creates a blocker through a one-click handoff — the blocker stays the one record that carries the actual stopped-work window, so any surface named "Delays" is really showing you blockers.
Note: "Delay" is user-facing copy for a contradicted dependency; the schema and events still say
violation. You'll see "delays" on the noticeboard banner and "blocker" everywhere a stoppage is recorded — they're two ends of the same story, not two competing records.
A raise is a suggestion, never an active blocker
SimOops does not mint an active blocker automatically. Every raise from the field enters as a suggestion and waits for a coordinator to look at it — the same shape as the safety-Observation and incident reviews. Triage is where a coordinator either agrees ("yes, that stopped work — confirm it") or waves it away ("I can stop that in five seconds — reject it").
suggest confirm
────────▶ suggested ─────────────────────────▶ confirmed ──▶ resolved ──▶ archived
│ (a live, counted blocker)
│ reject
▼
rejected (terminal — stays readable, but never counted)
A member's raise is a suggestion; a coordinator's (or QS's) direct declaration skips the queue and is confirmed at birth (self-confirmed — the commercial band raising its own record doesn't queue behind itself). Only a confirmed blocker is live, counts toward lost time, and appears site-wide. A rejected suggestion drops out of every active surface but stays on the record as an audit trail.
Note: There is no "reopen" edge. If a rejected situation recurs, it's a fresh suggestion with a fresh clock — the same discipline snags and permits use.
Who does what — the blocker_* band
Blockers are the commercial axis, so authority tracks it. The backend is always the source of truth; the UI simply hides controls you can't use.
| Role | View | Suggest | Declare / edit / resolve / snag-link | Confirm / reject | Acknowledge / archive / delete |
|---|---|---|---|---|---|
| viewer / client | ✅ | — | — | — | — |
| hse | ✅¹ | — | — | — | — |
| member | ✅ | ✅ | —² | — | — |
| commercial (QS) | ✅ | ✅ | ✅ | —³ | ✅ |
| coordinator / site manager / admin | ✅ | ✅ | ✅ | ✅ | ✅ |
¹ HSE reads blockers but never writes them. Blockers are commercial, deliberately kept off the safety axis — HSE's world stays observations, incidents, permits, RAMS and isolations. HSE sees blockers because every role with site access reads confirmed ones (see "where things surface"), not through any bespoke grant.
² A member's raise enters as a suggestion; a member may still edit their own still-suggested record, but every other correction happens in the confirm step, in the coordinator's hands.
³ The QS declares, edits, links and archives — but does not adjudicate triage. Confirm and reject are the coordinator band's (coordinator / site manager / admin). A suggestion "goes to the coordinator"; the QS is a first-class blocker author with lost_time_view, not a triage gatekeeper.
The three ways a blocker gets raised
Everything funnels into the same pre-filled confirm modal — the intake only decides whether the record enters suggested or confirmed.
- Mobile "Raise a blocker" — the phone-first stoppage surface. From the site home launcher, Raise a blocker asks "What's in the way?", lets you pick which of your own work today is stopped, defaults the stopped-headcount from that crew, and takes an optional photo, map point, and a "Whose stuff?" tag. It always enters suggested — "never auto-created active". Coordinator vocabulary (extent, snag links, knock-ons) is deliberately kept off the phone.
- Delay handoff (dependency violation) — when the dependency graph is contradicted, the noticeboard raises an uncollapsible "Delays" banner carrying a one-click, pre-filled declare-blocker handoff. Clicked by a coordinator it declares directly (confirmed); clicked by a member of the blocked trade it enters suggested for the same triage as any raise. Never an auto-declare — a human always declares the blocker.
- Desktop declare — a coordinator or QS uses Declare a blocker (with no location, or dropped at a map point) or turns a red clash into a blocker with "mark clash as blocker". Because the actor holds the declare permission, these enter confirmed at birth.
Note: A blocker carries the same fields whichever way it's raised — a cause, an extent, an actuals window, an optional note and photo, and optional affected work. At confirm, every field is coordinator-correctable: the confirm modal is a pre-filled declare form, not a bare "approve" button.
Blame is recorded at confirm, not at raise
Who's responsible for a stoppage is a commercial claim, so SimOops records it only when a coordinator confirms the blocker — never provisionally off a raise. At confirm, the modal pre-derives a likely responsible party from the cause chain (a delay points at the predecessor trade; every other cause starts blank), and the coordinator accepts, overrides, or clears it. That accepted value — and only that — is what the Lost time rollup attributes by.
A suggested blocker emits no attribution at all ("attribution pending"), so the lost-time numbers a QS reads never flicker on an unvetted grievance. The "Whose stuff?" tag a field user adds on the phone is exactly that — a hint that feeds the pre-derivation, not an accusation that lands until a coordinator signs off on it.
Rejecting a suggestion
Reject is a first-class outcome, not a failure. In the confirm modal, Reject… opens a reason box ("Why is this not a blocker?"), and Reject suggestion files it. Rejection:
- is terminal — there's no path back except a fresh raise;
- takes an optional reason, sent back to the person who raised it;
- stays readable to the suggester — a rejected record is audit trail, and "I can stop that in five seconds — close it" is itself a legitimate reject;
- is invisible to everyone else. An unvetted, possibly cross-trade grievance is not site-wide: a suggested or rejected blocker is visible only to its raiser and the commercial band. A third party asking for it gets a plain "not found", never a hint it existed.
Note: A genuinely junk suggestion can additionally be soft-deleted (reversibly) by the commercial band — the reject keeps the audit trail; the delete is the mistake path.
Where blockers surface
| Surface | What it shows |
|---|---|
| My Work → confirm_blocker task | The push channel. A new suggestion mints a Review suggestion task beside your incident approvals, and pings the coordinator band in-app and by email. The task auto-closes once you confirm or reject. |
| Completions → Blockers tab | The ledger home. A Suggested inbox (each row a pending triage badge + a Review… button that opens the shared confirm modal) sits on top of the confirmed Ledger — still-stopped rows floated to the top, knock-on blockers threaded beneath the cause they stem from. |
| Noticeboard → Blockers section | Confirmed records only. The noticeboard is not a suggestion home — there's no "Suggested (N)" strip here; the loud "Delays" banner is separate, and its handoff opens the very same confirm modal. |
The suggestion inbox and the ledger both read the same live store, so a confirm, reject, or resolve anywhere updates every surface at once.
The snag → blocker cause link
A blocker can name a Snag as its cause — a defect one trade left behind that is now stopping another. Crucially, that link is authored from the blocker side, by the commercial band (coordinator + QS), never by the person who logged the snag. A snag never raises a blocker by itself — "if it does, it's a coincidence". The band is the safeguard: linking is a claims instrument, so it lives with the people who own the commercial record, and a site-wide blocker only ever exposes the pointer to a snag, never a snag body the viewer couldn't already read.
See also: How activity reaches people · For coordinators. The authoritative terms live in the glossary — Blocker, Snag, Dependency violation and Lost time.