# Why a contractor can't be assigned to a job

> Every assignment runs one shared compliance gate. A contractor who lacks the service capability, a signed agreement, current insurance, or active availability is blocked with the exact reason — never silently omitted from the list. Extra credential requirements (a trade licence, a working-at-heights card) are opt-in per service, so turning compliance on for one service never makes the rest of your roster harder to dispatch.

URL: https://biloh.com.au/docs/concepts/why-a-contractor-cant-be-assigned
Category: Explanation | Audience: evaluator | Updated: 2026-08-07

Assignment in a field-service platform is the moment risk enters the business. Send an uninsured contractor to a commercial site and the exposure is real, immediate, and yours. So in Biloh every assignment — from the dispatch board, from an AI assistant over MCP, from any automated flow — runs the same **compliance gate** before the write happens.

The gate answers one question: *can this contractor be assigned to this service?* It returns either a pass (with any non-blocking warnings) or a block **with the exact reason**. There is no third state where a contractor quietly disappears from a picker.

## What does the gate actually check?

Four hard checks block an assignment:

- **Availability** — the contractor is active, not on leave or inactive.
- **A signed agreement** — the subcontractor agreement is signed. An unsigned or merely-sent agreement blocks.
- **Current insurance** — a *verified*, unexpired insurance document exists. An uploaded-but-unreviewed certificate is its own state and does not count as verified; nor does one that expired yesterday.
- **Service capability** — this contractor is registered as able to deliver *this specific service*. Being a cleaner does not make you configured for high-pressure work at height.

Alongside those, the gate returns **soft warnings** that never block: insurance expiring inside your warning window, a credential about to lapse, a coverage-area mismatch. Warnings inform the operator; they don't override their judgement.

## Why "blocked with a reason" matters more than it sounds

The tempting implementation is to filter the picker down to eligible contractors. It produces a clean list — and a dead end. When nobody qualifies, the operator sees an empty box and has no idea whether the roster is empty, the service is misconfigured, or somebody's certificate lapsed last Tuesday.

The rule Biloh follows instead: **the gate runs over every active contractor, and every non-candidate is returned with its failure reason.** An empty candidate list still carries a full blocked list — "no capability for this service", "insurance expired on that date", "agreement not signed" — which turns a dead end into a work queue. Each reason names its own remedy.

This also means the eligibility answer is the same everywhere. The dispatch board and an agent asking *"who can take this job?"* run the identical gate through one shared core, so the assistant never offers a contractor the assignment path would then refuse.

## Requirements you opt into, per service

Insurance and an agreement are the floor. Real trades need more: an electrical licence, a gas licence, a working-at-heights card, a plumbing registration. Biloh models these as **credential requirements attached to a service**, and the design constraint is deliberate:

> Requirements are opt-in and empty by default. A service with no requirements gates exactly as it did before the feature existed.

That constraint exists because the failure mode in field service is not contractors signing up too easily — it is contractors never finishing onboarding at all. A compliance system that makes every contractor harder to engage gets switched off, and then it protects nothing. So the model is: leave the floor where it is, and raise it deliberately, service by service, where the work genuinely demands it. A kill-switch setting disables requirement enforcement entirely without unpicking your configuration.

When a requirement is set and unmet, the block reads like the others — a named missing credential, not a generic refusal.

## Your own crew is not a subcontractor

If you perform work yourself rather than subcontracting it, your own crew is represented as an internal contractor and **bypasses the subcontractor gate** by default (it is your labour, your insurance, your business). That bypass is a setting, so an operator who wants their own crew held to the same evidence standard can have it. See [delivery models](/docs/concepts/delivery-models) for how self-perform, subcontract and hybrid businesses differ.

## What an operator does with a blocked list

Each reason maps to one action:

| Reason | What clears it |
| --- | --- |
| Not configured for this service | Add the service capability to the contractor |
| Agreement not signed | Send the subcontractor agreement for signature |
| No verified insurance / expired | Request a current certificate and verify it |
| Missing a required credential | Collect and verify that licence or card |
| On leave / inactive | Change availability, or pick someone else |

The practical shape of that work — and the trap where a contractor ticks their own capability boxes but the dispatcher still can't see them — is covered in [dispatching and triaging jobs](/docs/how-to/dispatching-and-triage) and, on the engineering side, in [two places, one fact](/docs/engineering-notes/two-places-one-fact).

## Related

- [Dispatching and triaging jobs](/docs/how-to/dispatching-and-triage)
- [Delivery models: dispatch, self-perform, or both](/docs/concepts/delivery-models)
- [Who decides whether a job needs photos?](/docs/concepts/completion-requirements-cascade)
- [Two places, one fact](/docs/engineering-notes/two-places-one-fact)
