AI Adoption GuideConstructionMobilize
Worker Competency Document Verification
ML with OCR validates worker licences, tickets, and medicals against role requirements and expiry dates at onboarding. (e.g., Procore AI)
Construction processBidAwardPlanMobilizeBuildInspectHandoverClose
By Don, DoneThat’s AI coach · updated
A cited pass or fail, not a green badge
The check answers one question for site access: does this person hold the licences, tickets, and medicals this role requires, and are those documents still in date on the evidence you actually have? The return is pass or fail, plus a cite to the file or page the model read and to the role requirement it scored.
A pass means the extracted fields support that requirement. A fail means they do not, or the evidence is too weak to decide. Fields the OCR could not read stay empty. Empty is not a badge.
HSE and site-access leads already keep this evidence in project systems. Construction platforms such as Procore and Autodesk Construction Cloud hold worker files, role lists, and induction packs. This check scores the pack against the role and writes a cite so a reviewer can open the same page the model used.
Do not auto-badge someone because a filename looks right or a folder is complete. If the role needs a high-risk work licence class the scan does not show, that requirement fails even if other tickets in the pack are clean.
Scan the ticket, match the role, stop on fail
Run this at onboarding, before site access for the role they will actually work. Do not run it against a generic worker profile if the roster has them as a dogman, scaffolder, or confined-space attendant.
Capture the ticket as a page image or PDF. Prefer a flat, well-lit capture of the whole face of the card. Cropping that cuts the name, class, or date block will force empty fields later.
OCR the ticket. Extract identity as printed, document type, class or endorsement, issuing body if present, and any date the card actually prints. Do not invent an expiry. If the card has no expiry line, leave expiry empty. If the date is unreadable, leave that field empty. Do not fill it from a sibling document in the same pack.
Match extracted type and class to the role matrix: which tickets and medicals this position needs, and whether each must be current. Matching is on the printed class, not on a nearby similar ticket. A general construction induction and a high-risk licence are different artefacts even when they sit in one wallet photo.
Score expiry only from what was read. If expiry is populated and it is before the planned start, or before today if that is your rule, that requirement fails. If expiry is empty because the scan did not yield a date, do not treat the ticket as current. That line stays undecided or fails per your gate rule. It does not pass.
Human confirms fails. Every fail, and every requirement left empty because the scan was unreadable, goes to a person who can open the cite. The reviewer accepts a better capture, records a genuine gap, or keeps the person off that role. Do not let the model rewrite a fail into a pass without a new document. Keep the cite next to the score: document identifier, page, extracted name and class, the role requirement wording, and whether expiry was read or left empty.
Empty fields and what a reviewer must open
Empty is a first-class result. Blur, glare, a folded card, or a camera too far from the date block should yield empty on the fields that failed, not a reconstructed date or a guessed class.
Do not auto-badge from a blurry photo. If name, class, or date cannot be read with confidence, the person is not verified for that requirement. Site access for that role stays closed until a readable capture exists or a reviewer records an equivalent they have opened outside this scan.
Name mismatch is a fail, not a spelling suggestion. If the OCR string does not match the person on the induction record, using only the matching rules you already apply for hyphens and middle names, stop. Matching the wrong name is how someone else's ticket becomes this worker's badge.
Other tickets in the same pack may still pass their own requirements. Do not roll those passes up into a role-level badge if a required ticket is empty or failed. Role access is conjunctive: every required artefact must pass with a cite. Give the reviewer the image crop the model used, not only a filename.
Example: dogman pack for a tower-crane crew
A tower-crane crew is due Monday. The site-access lead has a dogman on the subcontractor's roster. The role matrix requires a high-risk work licence in the dogging class, a current general construction induction, and a medical the principal contractor lists for crane-related roles.
The induction card is sharp: name matches the roster, class is the expected induction ticket, and the printed date fields are readable. That requirement can pass with a cite to that photo.
The high-risk licence photo is taken in a vehicle, laminated plastic flashing the date block. OCR returns the correct licence type and a matching name. The expiry field stays empty because the digits are not readable. That requirement does not pass. A person asks for a recapture or a portal download of the same licence.
The medical PDF is a letter. The name matches. Cite it on a pass only if the matrix accepts that class of medical for the period the letter actually states. Do not stretch a generic fitness note to cover a requirement it does not support.
Until the high-risk line has a readable date, or a reviewer records an equivalent they have opened, the dogman does not get the crane-crew badge. They may still pass a different role whose matrix they fully meet. This is the pattern: one pack, mixed pass and empty, no invented fields, no auto-badge.
Failure modes that look current
Reading an expired ticket as current. A faded year, a cropped corner, or a swapped day and month can make an expired card look in date. Never write an expiry the pixels do not support. Fail or empty when confidence on the date block is low. Put the crop in the cite so the reviewer sees the same digits.
Matching the wrong name. Wallet photos often contain two cards. A partner's ticket or a supervisor's licence in the same frame can OCR cleaner than the intended card. Bind the extracted name to the induction identity before class matching. If two names appear, fail so a human can split the image.
Badging from a blurry photo. A filename that looks like a licence plus a confident model is not evidence. Empty stays empty. No role-level pass while a required field is empty.
Class confusion is the same family of error. A working-at-heights training slip is not the high-risk licence class the matrix named. Match the printed class string to the requirement, not the folder the contractor used. Re-run against the role they will work this week. Last month's badge does not close a stricter matrix.
After the gate: skills, chasing, and site conditions
Document verification is the mobilize gate, not a skills assessment. A current dogging licence is not proof the person can run this crane's communications on this site. Once the pack passes, deployed workforce skills gap analysis asks who on the crew holds the task-level skills the work pack needs.
Missing artefacts after a fail are often a contractor process problem, not an OCR problem. Route repeated empty packs and overdue medicals through subcontractor compliance chasing agent so the access desk is not chasing PDFs by phone.
This check does not watch the live site. Once people are badged, real-time safety hazard detection and site setup compliance vision check cover conditions and setup, not whether the person who walked the gate held the right ticket. Keep those layers separate in the record. Mixing them into one "safe to start" flag hides which layer failed.
Is this worth automating for you?
Whether this pays back depends on how much time it takes your team today. Most teams estimate that from memory, and the estimate is usually wrong in one direction or the other.
DoneThat reconstructs where the time actually went, with no timers to forget, so you can measure the baseline before committing to a project and check the gain afterward.
Measure the baseline first