YardSight · multi-modal vehicle ID for ports & yards
Multi-modal gate automation for Tier-2/3 ports, intermodal terminals, large warehouse yards, and DOT weigh stations. Plate plus ISO 6346 container plus 17-character VIN plus USDOT plus HazMat placard — fused into one signed GateEvent per truck, in under three seconds. Recently pulled forward, the PRD-04 M3 + Post-1.0 capability surface: rail-mark OCR (AAR + UMLER), seal-tamper detection, damage assessment from imagery, and a 5-language operator UI — all in code today, with 215 tests passing in 2.3 s.
01 — Lane kinds
This is not a parking system, a tolling system, or a fleet-management system. It is built specifically for industrial gates where multiple identifiers must be read at once and reconciled against manifest sources. Each lane kind encodes its operational norms — what to surface, what to escalate.
— Lane · Port
ISO 6346 codes are the primary identifier. Manifests come from Navis or Tideworks. NO_CONTAINER is escalated. Plate + container + driver USDOT; HazMat enforcement; tractor / chassis pairing.
— Lane · Intermodal
Mixed container and trailer traffic. Manifests via Trimble or carrier APIs. Cross-modal reconciliation. Plate + container or trailer; FMCSA OOS hotlist; chassis-with-container detection.
— Lane · Warehouse
Plate is the primary identifier; bookings via WMS or project44. Lower escalation thresholds, faster gate-open. Plate + USDOT; booking-ref manifest match; walk-up tolerated.
— Lane · Weigh station
USDOT + plate against the FMCSA Out-of-Service list. Strict block on hotlist hits. HazMat manifest enforcement. USDOT + plate; FMCSA OOS daily refresh; HazMat UN + class enforcement.
02 — Drive-by aggregation
A truck driving through a gate is read by five cameras simultaneously: front-plate, side-container, rear-VIN, door-USDOT, hazmat placard. The aggregator fans those reads into a single DriveByResult — confidence-aware, check-digit validated, with bad-read rejection that beats raw OCR confidence.
# Five cameras fan into one DriveByAggregator (window = 3.0 s) [Camera 1 · plate ]──┐ [Camera 2 · container]──┤ [Camera 3 · VIN ]──┼──▶ DriveByAggregator ──▶ DriveByResult [Camera 4 · USDOT ]──┤ [Camera 5 · hazmat ]──┘ # Fusion rules per field plate highest plate_confidence · lexicographic tiebreak container_code highest confidence among reads that pass ISO 6346 check vin highest confidence among reads that pass NHTSA mod-11 usdot first non-empty wins trailer first non-empty wins hazmat_un first non-empty wins hazmat_class first non-empty wins classification first non-empty wins # A high-confidence-but-wrong read is still rejected by the check digit. from yardsight.aggregator import DriveByAggregator, Observation agg = DriveByAggregator(window_seconds=3.0, min_confidence=0.55) agg.submit(Observation(lane_id=1, camera_id=2, camera_role="container", seen_at=now, container_code="CSQU3054384", container_confidence=0.99)) # dropped result = agg.flush_all()[0] # result.container_code == "CSQU3054383" (the check-digit-valid one)
→ window default 3.0 s — generous for a truck at 8 km/h passing five cameras · flush_all() drains every open window at shutdown.
03 — Format validators
Industrial OCR is high-noise. A plain regex passes "CSQU3054384" because it has the right shape — but ISO 6346 arithmetic says the check digit is wrong. YardSight ships four code validators with full check-digit / check-char computation, structured parses, and exact compliance with the relevant standards.
Owner + category + serial + check digit. The check digit catches the most common OCR confusions: U→C, 0→O, and adjacent-digit transpositions. Reject value 10 per ISO 6346.
Check char at position 9 — "0"-"9" or "X" for value 10. I, O, Q are forbidden anywhere because they OCR like 1/0/0. The WMI / VDS / VIS substring decomposition is exposed in the parsed result.
Accepts every form OCR encounters: bare digits, "USDOT 12345", "U.S. DOT: 12345", "DOT 42". Strips prefixes, rejects leading zeros, validates the digit count.
UN-number range enforced. Hazard class (1.1, 2.3, 3, 5.1, 6.1, 9, …) parsed when present; bad classes are dropped from the parse rather than rejecting the placard.
04 — Manifest reconciliation
Every DriveByResult is reconciled against the manifest set active at the gate. The four outcomes are the engineering contract; the lane policy decides what to do with them. Plate matches are fuzzy (Levenshtein ≤ 1); container and VIN matches are exact.
— MATCH · auto-clear
Plate within 1 edit; container + VIN exact. Auto-clear the gate; no operator touch required. This is the 90% path on a healthy lane.
— MISMATCH · triage
Fires an exception at high severity. Operator console queues the event with a one-click resolve action. Block on hotlist hits; queue on data conflicts.
— PARTIAL · lane policy
Auto-clear at low-trust lanes; queue at port lanes. The lane kind decides — warehouses tolerate, ports do not.
— NO_MANIFEST · walk-up
Most warehouses allow it; port lanes do not. Persisted as a gate_exception with kind="UNMATCHED" and severity per lane policy.
Exceptions raised at process time are persisted to gate_exception with severity
(medium / high / critical), kind (MANIFEST_MISMATCH, HOTLIST_HIT, LOW_CONFIDENCE, NO_CONTAINER,
UNAUTHORISED), and a one-click resolve action from the operator console.
05 — TMS adapters
M0 ships four stub adapters that accept already-pulled manifest data and persist it into YardSight's normalised schema. M1 wires real HTTP / SOAP / webhook clients to each; the shape of the adapter API is stable from 1.0.
Each NavisBooking maps to one manifest row with source="navis". Real REST client ships in M1; Navis Marketplace certified at GA.
Loads with assigned tractor plate + VIN. Each TrimbleLoad maps to one manifest row with source="trimble".
Loaded via fmcsa_load_oos_csv(); persisted to hotlist with kind="usdot", source="fmcsa", 14-day default expiry. Federal grant funding usually covers the lane in Y1.
Project44Event.from_payload() accepts either CamelCase or snake_case key shapes; one event → one manifest row, source="project44".
05b — Capability horizon · M3 + Post-1.0 pulled forward
PRD-04 originally roadmapped multi-language UI for M2, rail-mark OCR for M3, and seal-tamper / damage assessment for Post-1.0. All four ship with real Protocol architecture and deterministic stub adapters today; production model adapters plug in behind the same Protocols. +55 tests; 215 pass in 2.3 s.
For intermodal terminals, Class-I railroads
15 Class-I North American operators covered (BNSF, UP, CSX, NS, CN, CP, KCS, GTW, IC, FXE, TFM, SAR, ARR, AC, WC). PlateKitRailMarkAdapter bridges PlateKit's platekit.rail_mark module into YardSight's drive-by aggregator — same fusion semantics as the other code classes.
For marine ports, customs, CTPAT-audited yards
SealDetector Protocol returns intact / missing / broken / obscured + the seal serial when intact. compare_seals() cross-checks gate-in vs gate-out for chain-of-custody breaks — the first time a yard sees a broken seal, it's an exception, not a missed read in next week's report.
For chassis pool ops, predictive maintenance
10-kind taxonomy (dent, scratch, rust, graffiti, door-misalignment, puncture, dripping_fluid, light_out, placard_missing, other) × 4 severity bands (cosmetic / minor / major / critical). needs_work_order() and is_out_of_service() decision helpers feed the TMS work-order push directly from the gate.
For multilingual yard crews
yardsight.i18n. en / es / zh / pt / hi covering web-UI labels, gate-event names, exception-triage templates, audit-log entries. Fallback-to-English semantics so missing translations never silently degrade operator UX — the gate keeps moving in whatever language the operator reads.
06 — Console & CLI
The FastAPI + HTMX console is server-rendered, runs on a single host at the gatehouse, and gives the operator the five views they need: dashboard, events list (filter by lane / manifest_status), event detail with raw per-camera reads, open exceptions queue with one-click resolve, lanes management. The CLI is how Tier-2/3 ports actually integrate.
Operator views
# 1. Initialise + define the gate. yardsight init --db /var/yardsight/yardsight.db yardsight lane --add --name east-gate \ --location "Port of Long Beach, Berth 22" --kind port # 2. Ingest manifests + hotlist (cron). yardsight ingest --navis navis-latest.json yardsight ingest --trimble trimble-latest.json yardsight ingest --fmcsa fmcsa-oos-$(date -u +%F).csv # 3. Process a drive-by from the edge agent (synchronous). yardsight process drive_by.json # event #1 status=match # manifest #7 matched=['plate','container'] mismatched=[] # 4. Walk the open exceptions queue + resolve. yardsight exceptions yardsight exceptions --resolve 4 \ --actor operator-1 \ --note "manifest verified by phone" # 5. Serve the dashboard. yardsight serve --port 8080
07 — Per-lane pricing
Plus class add-ons at $300–500/lane/month. Procurement-team conversation starts after the technical one finishes — not before. Posting our SKU sheet online and offering a 90-day paid pilot at $15K is itself the wedge.
First-look engagement
90 days · 2 lanes · paid
Standard subscription
Most ports
Per additional class
Plate · Container · VIN · USDOT · …
Multi-site + integrations
SAP TM · Oracle WMS · SOC 2
08 — Pilot
Skip the RFP. Run a paid pilot at one of your lanes, get measured accuracy on your traffic, and decide whether to expand. We bring the cameras, the appliance, and the install crew.