GuardCore · Patrols & proof
Proof the patrol happened, graded by the server
A checkpoint scan is judged on the server against the checkpoint, the guard, the tag’s own secret and the distance. The result the device claims is ignored.
The problem this solves
Every guard tour system on the market records scans. The question a client actually asks is different: can you show me that the guard was at that door, and not sitting in the car with the tag in their pocket?
Most products cannot, because the device decides. The phone reads a tag, decides the scan is valid, and posts that verdict; the server stores what it is told. A scan id the browser invented is indistinguishable from a real one, and a tag photographed once can be scanned from anywhere forever.
GuardCore inverts that. The phone reads the code and sends it; the server compares it against the checkpoint’s own secret in constant time, measures the distance against the checkpoint’s radius, and refuses the scan if it does not hold up. The device never receives the expected token, the coordinates or the radius, so there is nothing in the app to read the answer out of.
The refusal is not a discard. A rejected scan is stored as a rejected attempt and raises an alert for somebody to acknowledge — because the useful fact about a bad scan is that somebody made it.
Worked example
02:40. A scan arrives for a checkpoint on the far side of the site.
- 1
The token is compared, not trusted
Against the checkpoint’s stored secret, digest to digest in constant time, so the comparison cannot be timed to leak the answer a character at a time.
- 2
The distance is measured
Against that checkpoint’s own radius plus a fixed tolerance. The accuracy the device reports is recorded and deliberately not used to widen the allowance — a phone claiming a 400-metre error does not buy itself 400 metres.
- 3
The duplicate window is server time
Measured with the database’s own clock, so a backdated timestamp from the handset cannot walk around it.
- 4
It is refused, and kept
Stored as rejected, with an alert in the missed-alerts queue for a supervisor to acknowledge. The attempt is now part of the record rather than absent from it.
The scan that cannot be defended never becomes evidence, and the attempt to make it one is on file.
Capabilities
What patrols & proof gives you
7 of these 8 are in the product today; the rest carry a badge saying what they actually are. Each one names what it is built on.
The server grades the scan, not the phone
LiveEvery checkpoint scan is judged on the server against the checkpoint, the guard, the tag secret, the distance and the duplicate window — and the result the device claims is ignored.
The device never learns the answer
LiveA checkpoint’s secret, its coordinates and its radius are excluded from every read a phone can reach, and the comparison is constant-time, so the tag cannot be cloned from the app that scans it.
A refused scan is kept, not discarded
LiveA fabricated or out-of-place scan is refused as proof and kept as an attempt, with an alert raised for someone to acknowledge — because the interesting thing about a bad scan is that somebody tried it.
NFC, QR or the printed code
LiveThe phone reads the tag itself — NFC on Android, the camera anywhere, or the printed code typed by hand on iPhone, where the browser has no NFC — and captures a high-accuracy fix with it.
The tour nobody started
LiveA scheduled tour that produced no patrol leaves no row to notice, so a background sweep grades every settled occurrence on time, late or missed and notifies the site’s supervisors and the customer’s own portal users.
Patrol log register
LiveEvery patrol with its site, its guard, its start and finish and the exceptions raised against it, filterable and exportable — the register someone opens when a client asks about last Tuesday.
Geofences that act, not just draw
LiveCircles and polygons per site, typed as boundary, restricted, patrol or parking, each with its own entry and exit action — and an exit set to escalate starts the escalation chain rather than writing a line nobody reads.
Building a tour route on screen
RoadmapSequencing checkpoints into a route with an expected offset and a window per stop. The table exists and only the data importer writes it, so a route can be migrated in and not yet built on screen.
On the roadmap. It is not built, not scheduled, and not something to plan a contract around.
What backs these claims
Each capability names the decision record, module, route or table it is built on. Ask us for any of them in an evaluation and we will walk you through the code.
- The server grades the scan, not the phone
- src/server/imss-checkpoint-scan-rules.ts validateScan · src/server/api/imss/checkpoints/scans.ts createScan · POST /api/imss/checkpoints/scans
- The device never learns the answer
- ADR 0012 · src/server/api/imss/mobile/GET.ts CHECKPOINT_COLUMNS · src/server/imss-checkpoint-scan-rules.ts tokensMatch
- A refused scan is kept, not discarded
- src/server/api/imss/checkpoints/scans.ts listMissedAlerts · GET /api/imss/checkpoints/missed-alerts · imss_checkpoint_scans
- NFC, QR or the printed code
- src/lib/checkpoint-scan.ts readNfcTag readBarcodeFromVideo capturePosition · ADR 0038
- The tour nobody started
- ADR 0050 · src/server/imss-tour-compliance.ts gradeTour · src/server/imss-jobs/tour-compliance.ts sweepTourCompliance · GET /api/imss/tour-compliance
- Patrol log register
- GET /api/imss/patrol-logs · /imss/patrol · OpsPatrol.tsx · imss_patrol_logs
- Geofences that act, not just draw
- src/server/imss-guard-safety.ts containsPoint · src/server/api/imss/v3/safety-cases.ts geofenceEventCreate · /imss/geofencing · imss_geofences
- Building a tour route on screen
- imss_tour_checkpoints · src/scripts/imss-maintenance/migration-import.ts
Where this sits
Back to
GuardCore — every capability in one place
The whole module: what is live, and what is only on the roadmap.
Read next
Incidents with a clock that escalates without being asked
An acknowledgement clock and a response clock, each scaled by severity and measured against the site’s own minutes — swept in the background, escalated once per level.
Twenty minutes on a real contract.
Real data, four logins, nothing typed on the day — including the parts we have not built, which we will point out ourselves.