Skip to content
Core Architecture

FMCSA DVIR Rule 396.11 Breakdown

Every automated Driver Vehicle Inspection Report (DVIR) pipeline ultimately answers to one statute: 49 CFR § 396.11. The engineering problem this page solves is turning that regulation’s prose — driver attestation, defect documentation, repair certification, and record retention — into a set of enforceable gates that a data pipeline physically cannot bypass. The regulatory hook is § 396.11©(2): a motor carrier must certify that a reported safety-affecting defect was repaired, or that repair was unnecessary, before the vehicle is dispatched again, and § 396.11©(2)(iii) requires the next driver to review and sign that certification. Miss either signature and the record is a Vehicle Maintenance BASIC violation waiting to surface in a roadside inspection. This breakdown sits inside the Core DVIR Architecture & FMCSA Compliance Mapping reference and maps each sub-clause of § 396.11 to the exact ingestion contract, schema field, routing decision, and audit event a compliant system must implement. Treat § 396.11 not as a paper form but as a deterministic state machine that governs vehicle release, defect escalation, and repair certification.

Prerequisites and Environment Setup

Anchor link to "Prerequisites and Environment Setup"

This breakdown assumes a Python 3.10+ service that receives DVIR payloads from a mobile client or telematics gateway and persists audit-ready records. The clause-to-code mapping below builds on the canonical model defined in the Standardized DVIR JSON Schema Design guide, and it consumes the defect vocabulary from Defect Taxonomy Mapping for Heavy Trucks. Install the following before implementing the gates:

  • pydantic>=2.6 — runtime validation and JSON Schema generation for the ingestion contract.
  • jsonschema>=4.21 — draft 2020-12 validation with custom format checkers (UUID, VIN, ISO 8601).
  • hashlib (stdlib) — SHA-256 evidentiary hashing for tamper-evident audit chaining.
  • python-dateutil>=2.9 — strict timezone-aware timestamp parsing for offline reconciliation.

The parent architecture supplies two contracts this page depends on: the versioned DVIRRecord schema (the shape every payload is coerced into) and the DefectSeverity enum with its 0–34 / 35–69 / 70–100 scoring bands. Keep those field names identical here so downstream classification and the Compliance Boundary Enforcement in Cloud Workflows audit layer read the same signals.

Clause-to-Field Mapping: The § 396.11 Data Contract

Anchor link to "Clause-to-Field Mapping: The § 396.11 Data Contract"

Rule 396.11(a) requires a written report at the completion of each day’s work covering, at minimum, the service brakes, parking brake, steering mechanism, lighting devices and reflectors, tires, horn, windshield wipers, rear-vision mirrors, coupling devices, wheels and rims, and emergency equipment. Under § 396.11(a)(3), any defect that would affect safe operation or cause a mechanical breakdown must be documented. Each statutory obligation maps to a concrete field, type, and compliance action in the ingestion contract:

CFR clause Obligation Schema field Type / enum Compliance action if absent
§ 396.11(a) Written report per vehicle per day dvir_id, report_date UUID, date Reject the payload at the API boundary
§ 396.11(a) Driver identity attestation driver_cdl_hash str (SHA-256) Reject; return to client for authentication
§ 396.11(a) Vehicle identification vehicle_vin, unit_number str (17-char VIN), str Reject; unresolved VIN cannot enter pipeline
§ 396.11(a)(3) Defect documentation defects[] list[Defect] Coerce empty list to no_defects attestation
§ 396.11(a)(3) Defect severity defects[].severity CRITICAL/MAJOR/MINOR/NONE Route by band; CRITICAL triggers an OOS hold
§ 396.11©(2) Repair certification repair_certification RepairCertification | None Block return-to-service transition
§ 396.11©(2)(iii) Next-driver review signature review_signature Signature | None Block finalization of prior report

The subtle compliance failure most pipelines miss is the empty defect array. A driver submitting “no defects” is making an affirmative attestation under § 396.11(a), not sending a null payload. Coerce an empty defects[] into an explicit certification_status: "no_defects" flag rather than treating it as missing data — the distinction is the difference between a signed clean report and an incomplete record during a DOT audit.

python
from __future__ import annotations

from datetime import date, datetime
from enum import Enum
from uuid import UUID

from pydantic import BaseModel, Field, field_validator


class DefectSeverity(str, Enum):
    # Bands align with the parent architecture's scoring model and DOT OOS criteria.
    CRITICAL = "critical"   # score 70-100: OOS condition, immobilize before dispatch
    MAJOR = "major"         # score 35-69: repair within regulated window
    MINOR = "minor"         # score 0-34: schedule at next maintenance interval
    NONE = "none"


class CertificationStatus(str, Enum):
    NO_DEFECTS = "no_defects"       # § 396.11(a) affirmative clean attestation
    DEFECTS_LISTED = "defects_listed"
    REPAIR_CERTIFIED = "repair_certified"  # § 396.11(c)(2)


class Defect(BaseModel):
    defect_code: str                      # controlled vocabulary; see Defect Taxonomy Mapping
    component: str                        # e.g. "BRAKES", "STEERING", "LIGHTING"
    severity: DefectSeverity
    description: str | None = None


class DVIRRecord(BaseModel):
    dvir_id: UUID                         # § 396.11(a): client-generated idempotency key
    driver_cdl_hash: str                  # § 396.11(a): driver attestation identity
    vehicle_vin: str = Field(min_length=17, max_length=17)
    unit_number: str
    report_date: date                     # drives the 3-month retention window
    inspected_at: datetime                # must be timezone-aware (UTC)
    defects: list[Defect] = Field(default_factory=list)
    certification_status: CertificationStatus

    @field_validator("inspected_at")
    @classmethod
    def require_tz(cls, v: datetime) -> datetime:
        if v.tzinfo is None:
            raise ValueError("inspected_at must be timezone-aware; reject the payload")
        return v

Core Workflow: The § 396.11 State Machine

Anchor link to "Core Workflow: The § 396.11 State Machine"

Section 396.11(b) requires that a defect affecting safe operation be corrected before the vehicle returns to service, and § 396.11©(2) requires the carrier to certify that correction. This creates a mandatory handshake in the compliance state machine: INSPECTED → (defect present) REPAIREDRELEASED, with a clean report shortcutting straight from INSPECTED to RELEASED. The transition into RELEASED from REPAIRED cannot occur without both a mechanic certification and the next driver’s review signature under § 396.11©(2)(iii).

The § 396.11 return-to-service state machine A left-to-right state machine. A driver completing the DVIR under § 396.11(a) enters the INSPECTED state. From INSPECTED, a clean report with no safety-affecting defect transitions directly to RELEASED. If a defect is present, the vehicle transitions to REPAIRED only once a mechanic certifies the repair under § 396.11(c)(2). The REPAIRED-to-RELEASED transition is a gated handshake that requires the next driver to review and sign the prior report under § 396.11(c)(2)(iii); both the mechanic certification and the review signature must be present or the release is blocked. RELEASED is the terminal accepted state. driver § 396.11(a) INSPECTED DVIR completed & signed No safety-affecting defect direct release Defect present REPAIRED mechanic certifies § 396.11(c)(2) Next driver reviews & signs § 396.11(c)(2)(iii) RELEASED return to service Gated handshake — both signatures required 1. Mechanic certification (SHA-256 signed) — § 396.11(c)(2) 2. Next-driver review signature — § 396.11(c)(2)(iii) Missing either ⇒ block the release, hold the unit.

The gate that enforces the handshake must reject any transition that lacks its required signatures. Model the transition explicitly so an out-of-band write to the RELEASED state is impossible:

python
from dataclasses import dataclass


@dataclass(frozen=True)
class RepairCertification:
    mechanic_id: str
    certified_at: datetime
    signature_hash: str          # SHA-256 of the mechanic's signed payload


LEGAL_TRANSITIONS: dict[str, set[str]] = {
    "INSPECTED": {"RELEASED", "REPAIRED"},
    "REPAIRED": {"RELEASED"},
    "RELEASED": set(),
}


def transition(
    record: DVIRRecord,
    current: str,
    target: str,
    certification: RepairCertification | None,
    review_signature: str | None,
) -> str:
    if target not in LEGAL_TRANSITIONS[current]:
        raise ValueError(f"Illegal transition {current} -> {target}; reject")

    has_critical = any(d.severity == DefectSeverity.CRITICAL for d in record.defects)

    # § 396.11(b): a safety-affecting defect blocks a direct release.
    if current == "INSPECTED" and target == "RELEASED" and has_critical:
        raise ValueError("Safety-affecting defect present; route to OOS hold")

    # § 396.11(c)(2): return-to-service requires mechanic certification...
    if current == "REPAIRED" and target == "RELEASED":
        if certification is None:
            raise ValueError("Missing mechanic certification; block release")
        # ...and § 396.11(c)(2)(iii): next-driver review signature.
        if not review_signature:
            raise ValueError("Missing next-driver review signature; block release")

    return target

Compliance Thresholding and Routing

Anchor link to "Compliance Thresholding and Routing"

The operational core of § 396.11 is distinguishing defects that require repair before dispatch from those that do not affect safety. Map the computed severity band to a compliance action using the same thresholds the parent architecture defines, so the classifier, the router, and the audit log all agree. A CRITICAL band is an out-of-service condition and must immobilize the vehicle; a MAJOR band enters the regulated repair window; a MINOR band is scheduled maintenance:

Severity band Tier Compliance action Routing
0–34 Minor Log for next scheduled PM Queue for standard bay assignment
35–69 Major Flag for pre-trip clearance Route to the classification engine for expedited triage
70–100 Critical / OOS Immediate immobilization required Trigger emergency dispatch and a compliance hold

Critical tags must trigger synchronous alerts to maintenance dispatchers and enforce a HOLD state on the vehicle until a certified mechanic intervenes. The routing decision is downstream of ingestion but upstream of repair certification, and it feeds the Defect Classification & Repair Routing engine that converts a graded defect into a tracked repair order. For the exact field-level correlation between a raw mobile payload and each § 396.11 obligation, follow How to Map DVIR Fields to FMCSA 396.11 Requirements, which walks identity resolution, temporal normalization, and defect-array coercion end to end.

Severity-band routing to § 396.11 compliance lanes A computed defect severity score fans out to three compliance lanes by band. A score of 0 to 34 is a minor defect and routes to the scheduled preventive-maintenance queue for standard bay assignment. A score of 35 to 69 is a major defect and routes to the regulated repair window for expedited triage. A score of 70 to 100 is a critical, out-of-service defect that triggers immediate immobilization and a compliance hold. Both the critical out-of-service lane and the completed repair-window lane converge on the repair-certification gate, which enforces the mechanic certification under § 396.11(c)(2) and the next-driver review signature under § 396.11(c)(2)(iii) before the vehicle can be released. The minor lane releases directly through scheduled maintenance without the gate. Severity score deterministic · 0–100 70–100 · CRITICAL / OOS Immobilize + compliance hold emergency dispatch · unit held 35–69 · MAJOR Regulated repair window expedited triage · pre-trip clearance 0–34 · MINOR Scheduled PM queue standard bay assignment Repair-certification gate mechanic cert · § 396.11(c)(2) driver review · § 396.11(c)(2)(iii) both required to release direct release · no gate

Production Integration and Platform Synchronization

Anchor link to "Production Integration and Platform Synchronization"

Once a record is classified and its state resolved, the pipeline must emit the outcome to the systems that act on it: the computerized maintenance management system (CMMS) that opens the work order, the telematics or ELD platform that surfaces the OOS status to dispatch, and the audit store that preserves the evidence. Emit each transition as an idempotent event keyed on the client-generated dvir_id, so a mobile client retrying after an offline gap never creates a duplicate compliance record. Chain the events with SHA-256 so the audit ledger is tamper-evident:

python
import hashlib
import json


def audit_event(record: DVIRRecord, transition_to: str, prev_hash: str) -> dict:
    payload = {
        "dvir_id": str(record.dvir_id),
        "vehicle_vin": record.vehicle_vin,
        "state": transition_to,
        "report_date": record.report_date.isoformat(),
        "prev_hash": prev_hash,           # links to the prior audit entry
    }
    body = json.dumps(payload, sort_keys=True, separators=(",", ":"))
    payload["event_hash"] = hashlib.sha256(body.encode()).hexdigest()
    return payload

Retention is itself a § 396.11 obligation: § 396.11©(2)(iii) requires the signed report and its repair certification to be kept for at least three months from the preparation date. Drive purge scheduling from report_date, not ingestion time, so an offline-delayed submission still retains the full regulated window. Persist the signed record and certification together in Write-Once-Read-Many (WORM) storage, keyed by VIN and preparation date for DOT audit access. The append-only chaining and role-gated writes are specified in Compliance Boundary Enforcement in Cloud Workflows.

  • Schema validation: every payload is validated against the versioned DVIRRecord contract before any business rule runs; reject malformed submissions at the API boundary.
  • Deterministic execution: the severity band and the OOS trigger run through auditable rule-based logic, not a model, so the decision is reproducible in an audit.
  • Empty-array coercion: an empty defects[] becomes an explicit no_defects attestation, never silent missing data.
  • Gated transitions: RELEASED is unreachable from REPAIRED without a mechanic certification (§ 396.11©(2)) and a next-driver review signature (§ 396.11©(2)(iii)).
  • Idempotency: every audit event is keyed on dvir_id; retries never duplicate compliance records.
  • Audit logging: each accepted transition emits a SHA-256-chained event to WORM storage.
  • Retention scheduling: purge windows are driven by report_date and enforce the three-month § 396.11©(2)(iii) minimum.
What exactly does 49 CFR § 396.11 require a driver to report?

Under § 396.11(a) the driver must prepare a written report at the end of each day’s work for every vehicle operated, covering at minimum the service brakes, parking brake, steering mechanism, lighting devices and reflectors, tires, horn, windshield wipers, rear-vision mirrors, coupling devices, wheels and rims, and emergency equipment. Under § 396.11(a)(3), any defect affecting safe operation or likely to cause a breakdown must be documented, and the driver must sign the report.

When can a vehicle return to service after a defect is reported?

Only after § 396.11(b) and ©(2) are satisfied: the safety-affecting defect must be corrected, the carrier must certify the repair (or certify that repair was unnecessary), and under § 396.11©(2)(iii) the next driver must review and sign the prior report. In the state machine, REPAIRED cannot transition to RELEASED without both the mechanic certification and the next-driver review signature.

How long must a DVIR be retained under § 396.11?

At least three months from the date the report was prepared, per § 396.11©(2)(iii). Store the signed report and its repair certification together in WORM storage and drive purge scheduling from the preparation date so that offline-delayed submissions are retained for the full window.

How should a “no defects” submission be handled in code?

Coerce an empty defects[] array into an explicit certification_status: "no_defects" flag rather than treating it as missing data. The driver is making an affirmative attestation under § 396.11(a) that the vehicle is safe, and that signed attestation must be preserved as a distinct, auditable state.

Back to Core DVIR Architecture & FMCSA Compliance Mapping.