Skip to content

Latest commit

 

History

History
1060 lines (709 loc) · 30.9 KB

File metadata and controls

1060 lines (709 loc) · 30.9 KB

Rule catalog

All rules below validate against TODS v2.1.0. Severities:

  • ERROR: the feed violates the spec; consumers may misread or drop data.
  • WARNING: probably a mistake, but the spec does not forbid it.
  • INFO: worth knowing; no action required.

Rules that resolve IDs into the companion GTFS feed run only when one is available (via --gtfs or GTFS files alongside the TODS files).

Package and file structure (TODS-x1xx)

TODS-W101: No TODS files in package

Severity: WARNING.

The package contains none of the files defined by the TODS spec version being validated against. Every TODS file is optional, but a package with none of them has nothing to validate.

Example ((package root)):

Before:

agency.txt
notes.txt

After:

agency.txt
notes.txt
run_events.txt
vehicles.txt

Every TODS file is optional, but the package needs at least one to validate.

Spec reference: https://tods-transit.org/spec/#files

TODS-I102: File is not part of TODS or GTFS

Severity: INFO.

A file in the package is neither a TODS file nor a standard GTFS file. It is ignored by this validator.

Example (notes.txt):

Before:

note
remember to update this feed

After:

(remove notes.txt, or rename it to a filename TODS or GTFS defines)

Not an error: the file is simply skipped. Fix the name if it was meant to be a TODS file.

Spec reference: https://tods-transit.org/spec/#files

TODS-E103: File could not be read

Severity: ERROR.

A TODS file is empty, not UTF-8 encoded, or not parseable as CSV. The file's contents were not validated.

Example (vehicles.txt):

Before:

(empty file)

After:

vehicle_id,vehicle_label
bus-1,Old Reliable

An empty, non-UTF-8, or unparseable file cannot be read at all; write at least a header row in UTF-8.

Spec reference: https://tods-transit.org/spec/#files

TODS-E104: Row has the wrong number of values

Severity: ERROR.

A row has more or fewer values than the file's header declares columns. Values after the mismatch may be attributed to the wrong field.

Example (vehicles.txt):

Before:

vehicle_id,vehicle_label
bus-1,Old Reliable,extra-value

After:

vehicle_id,vehicle_label
bus-1,Old Reliable

The row has three values but the header declares two columns; drop the stray trailing value.

Spec reference: https://tods-transit.org/spec/#files

TODS-E105: Duplicate column name

Severity: ERROR.

A column name appears more than once in a file's header row.

Example (vehicles.txt):

Before:

vehicle_id,vehicle_id
bus-1,bus-1

After:

vehicle_id,vehicle_label
bus-1,Old Reliable

Rename the duplicated header so every column name in the file is unique.

Spec reference: https://tods-transit.org/spec/#files

TODS-E106: Required column is missing

Severity: ERROR.

A TODS file does not declare a column the spec marks Required (for supplement files: a primary-key column of the GTFS file being supplemented). Rows cannot be interpreted without it.

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,start_location,start_time,end_location,end_time
daily,1,1,garage,08:00:00,garage,08:00:00

After:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,1,Report,garage,08:00:00,garage,08:00:00

event_type is Required; add the missing column.

Spec reference: https://tods-transit.org/spec/

TODS-W107: Column is not defined by TODS

Severity: WARNING.

A TODS-specific file declares a column the spec does not define. Consumers will ignore it; it is often a misspelled field name.

Example (vehicles.txt):

Before:

vehicle_id,vehicle_nickname
bus-1,Buster

After:

vehicle_id,vehicle_label
bus-1,Buster

vehicle_nickname is not a defined TODS field and consumers will ignore it; rename it to the field you meant (here, vehicle_label) or drop it.

Spec reference: https://tods-transit.org/spec/

TODS-I108: Supplement column is not defined by GTFS or TODS

Severity: INFO.

A supplement file declares a column that is neither a field of the GTFS file being supplemented nor a TODS_ field. It is carried through to the merged feed as a GTFS extension field.

Example (stops_supplement.txt):

Before:

stop_id,my_custom_note
garage,internal only

After:

stop_id,TODS_my_custom_note
garage,internal only

Not an error: the column is carried into the merged GTFS as an extension field. Prefix it TODS_ if it should stay TODS-only metadata instead.

Spec reference: https://tods-transit.org/spec/#supplement-files

Field values (TODS-x2xx)

TODS-E201: Required value is missing

Severity: ERROR.

A field the spec marks Required is empty. Supplement primary-key fields are always required; a row that adds a new GTFS entry must also provide every field GTFS marks Required for that file.

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,1,,garage,08:00:00,garage,08:00:00

After:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,1,Report,garage,08:00:00,garage,08:00:00

event_type is Required and cannot be blank; supply a value.

Spec reference: https://tods-transit.org/spec/

TODS-E202: Value is not an allowed option

Severity: ERROR.

An enum field has a value outside the options the spec allows (TODS_delete: blank or 1; start_mid_trip and end_mid_trip: blank, 0, 1, or 2).

Example (stops_supplement.txt):

Before:

stop_id,TODS_delete
garage,yes

After:

stop_id,TODS_delete
garage,1

TODS_delete only accepts 1 (or blank); 'yes' is not one of the allowed options.

Spec reference: https://tods-transit.org/spec/

TODS-E203: Value has the wrong format

Severity: ERROR.

A value does not match its field type: times must be HH:MM:SS (hours may exceed 24 for service after midnight), dates must be YYYYMMDD, event_sequence must be a non-negative whole number, latitudes must be a decimal degree in -90..90, longitudes a decimal degree in -180..180, and shape_dist_traveled a non-negative decimal number.

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,1,Report,garage,9am,garage,08:00:00

After:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,1,Report,garage,09:00:00,garage,08:00:00

Times must be HH:MM:SS (values past 24:00:00 are allowed for post-midnight events); '9am' does not match the format.

Spec reference: https://tods-transit.org/spec/

TODS-E204: Duplicate primary key

Severity: ERROR.

Two rows in a TODS-specific file share the same primary key (run_events: service_id + run_id + event_sequence; vehicles: vehicle_id; employee_run_dates: date + service_id + run_id + employee_id; vehicle_assignments: date + block_id + service_id). Consumers cannot tell the rows apart.

Example (vehicles.txt):

Before:

vehicle_id,vehicle_label
bus-1,Old Reliable
bus-1,Duplicate

After:

vehicle_id,vehicle_label
bus-1,Old Reliable
bus-2,Duplicate

vehicle_id is the primary key; give the second row its own ID.

Spec reference: https://tods-transit.org/spec/

TODS-E205: vehicle_assignments needs service_id to be unambiguous

Severity: ERROR. Needs a companion GTFS feed.

service_id in vehicle_assignments.txt is required when the same block_id is used by more than one service. Without it, the assignment cannot be matched to a single block.

Example (vehicle_assignments.txt):

Before:

date,service_id,block_id,vehicle_id
20260106,,B1,bus-1

After:

date,service_id,block_id,vehicle_id
20260106,weekday,B1,bus-1

trips.txt reuses block_id B1 across more than one service, so service_id must be filled in to say which one this assignment is for.

Spec reference: https://tods-transit.org/spec/#vehicle_assignmentstxt

TODS-W206: Value has leading or trailing spaces

Severity: WARNING.

A value is padded with spaces. IDs with stray spaces will not match the records they reference, and consumers are not required to trim them.

Example (vehicles.txt):

Before:

vehicle_id,vehicle_label
bus-1 ,Old Reliable

After:

vehicle_id,vehicle_label
bus-1,Old Reliable

Leading/trailing spaces are kept as part of the value by most parsers and silently break exact-match lookups elsewhere in the feed. tods-validate fix trims these automatically.

Spec reference: https://tods-transit.org/spec/

References between files (TODS-x3xx)

TODS-E301: Employee assignment points to a run that does not exist

Severity: ERROR.

A row in employee_run_dates.txt names a (service_id, run_id) pair that has no events in run_events.txt. The assignment cannot be matched to a run.

Example (employee_run_dates.txt):

Before:

date,service_id,run_id,employee_id
20260106,daily,2,emp-1

After:

date,service_id,run_id,employee_id
20260106,daily,1,emp-1

run_id 2 has no run_events.txt rows under service_id daily; point at a run that actually exists (here, 1).

Spec reference: https://tods-transit.org/spec/#employee_run_datestxt

TODS-W302: Referenced file is missing, references not checked

Severity: WARNING.

A file references another file that is not in the package (or, for GTFS targets, not in the companion feed), so those references could not be validated.

Example (employee_run_dates.txt):

Before:

date,service_id,run_id,employee_id
20260106,daily,1,emp-1  # run_events.txt is not in this package

After:

(add run_events.txt to the package, or pass the correct --gtfs/path)

Without run_events.txt, run_id references cannot be checked at all; this is a warning because the file may simply be outside the current validation pass, not necessarily missing from the real feed.

Spec reference: https://tods-transit.org/spec/

TODS-E303: Vehicle assignment points to a vehicle that does not exist

Severity: ERROR.

A row in vehicle_assignments.txt names a vehicle_id that is not defined in vehicles.txt.

Example (vehicle_assignments.txt):

Before:

date,service_id,block_id,vehicle_id
20260106,daily,B1,bus-9

After:

date,service_id,block_id,vehicle_id
20260106,daily,B1,bus-1

vehicle_id bus-9 is not defined in vehicles.txt; assign an existing vehicle.

Spec reference: https://tods-transit.org/spec/#vehicle_assignmentstxt

TODS-E304: Supplement both deletes and redefines the same row

Severity: ERROR.

A supplement file contains a delete (TODS_delete=1) and another row with the same primary key. The spec prohibits this because supplement rows are not processed in order, so the result is undefined.

Example (stops_supplement.txt):

Before:

stop_id,stop_name,TODS_delete
s1,,1
s1,Replacement Name,

After:

stop_id,stop_name,TODS_delete
s1,Replacement Name,

s1 appears twice: once deleted, once redefined, which is contradictory. Keep a single row per stop_id.

Spec reference: https://tods-transit.org/spec/#supplement-files

TODS-W305: Supplement updates the same row more than once

Severity: WARNING.

A supplement file contains multiple non-delete rows with the same primary key. Supplement rows are not processed in order, so which values win is undefined.

Example (stops_supplement.txt):

Before:

stop_id,stop_name,TODS_delete
s1,Name A,
s1,Name B,

After:

stop_id,stop_name,TODS_delete
s1,Name B,

Two rows update the same stop_id; the merge applies them in file order, so the first update is silently overwritten. Keep one row per primary key.

Spec reference: https://tods-transit.org/spec/#supplement-files

TODS-W306: Deleted supplement row carries values that will be ignored

Severity: WARNING.

A supplement row sets TODS_delete=1 and also fills in other fields. The spec says the row is removed and the other values are ignored.

Example (stops_supplement.txt):

Before:

stop_id,stop_name,TODS_delete
s1,New Name,1

After:

stop_id,stop_name,TODS_delete
s1,,1

A deleted row's other columns are never applied; clear them so the file doesn't imply the rename survives.

Spec reference: https://tods-transit.org/spec/#supplement-files

TODS-E307: Run event points to a trip that does not exist

Severity: ERROR. Needs a companion GTFS feed.

A run event names a trip_id that is not in the companion GTFS trips.txt after supplements are applied.

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,event_type,trip_id,start_location,start_time,end_location,end_time
daily,1,1,Operator,ghost-trip,s1,08:00:00,s2,09:00:00

After:

service_id,run_id,event_sequence,event_type,trip_id,start_location,start_time,end_location,end_time
daily,1,1,Operator,t1,s1,08:00:00,s2,09:00:00

trip_id ghost-trip is not defined in trips.txt; point at a real trip (here, t1).

Spec reference: https://tods-transit.org/spec/#run_eventstxt

TODS-E308: Run uses a service that does not exist

Severity: ERROR. Needs a companion GTFS feed.

A run event names a service_id that is not defined in the companion GTFS calendar.txt or calendar_dates.txt after supplements are applied.

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
ghost,1,1,Report,garage,08:00:00,garage,08:00:00

After:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,1,Report,garage,08:00:00,garage,08:00:00

service_id ghost is not defined in calendar.txt/calendar_dates.txt; use a service that exists (here, daily).

Spec reference: https://tods-transit.org/spec/#run_eventstxt

TODS-E309: Run event starts or ends at a stop that does not exist

Severity: ERROR. Needs a companion GTFS feed.

A run event's start_location or end_location is not in the companion GTFS stops.txt after supplements are applied.

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,1,Report,ghost-stop,08:00:00,s1,08:00:00

After:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,1,Report,s1,08:00:00,s1,08:00:00

ghost-stop is not defined in stops.txt; use a stop_id that exists.

Spec reference: https://tods-transit.org/spec/#run_eventstxt

TODS-E310: Run event block disagrees with the trip's block

Severity: ERROR. Needs a companion GTFS feed.

A run event sets both block_id and trip_id, and the trip's block_id in the supplemented GTFS feed is different. The spec requires the two to match when both are set.

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,event_type,trip_id,block_id,start_location,start_time,end_location,end_time
daily,1,1,Operator,t1,B2,s1,08:00:00,s2,09:00:00

After:

service_id,run_id,event_sequence,event_type,trip_id,block_id,start_location,start_time,end_location,end_time
daily,1,1,Operator,t1,B1,s1,08:00:00,s2,09:00:00

trips.txt says trip t1 belongs to block B1, but this event claims block_id B2; the two must agree.

Spec reference: https://tods-transit.org/spec/#run_eventstxt

TODS-E311: Vehicle assignment points to a block that does not exist

Severity: ERROR. Needs a companion GTFS feed.

A vehicle assignment names a block_id that no trip uses in the companion GTFS feed after supplements are applied.

Example (vehicle_assignments.txt):

Before:

date,service_id,block_id,vehicle_id
20260106,daily,B9,bus-1

After:

date,service_id,block_id,vehicle_id
20260106,daily,B1,bus-1

block_id B9 is not used by any trip in trips.txt; assign a block that is actually scheduled.

Spec reference: https://tods-transit.org/spec/#vehicle_assignmentstxt

TODS-E312: Vehicle assignment uses a service that does not exist

Severity: ERROR. Needs a companion GTFS feed.

A vehicle assignment names a service_id that is not defined in the companion GTFS calendars after supplements are applied.

Example (vehicle_assignments.txt):

Before:

date,service_id,block_id,vehicle_id
20260106,ghost,B1,bus-1

After:

date,service_id,block_id,vehicle_id
20260106,daily,B1,bus-1

service_id ghost does not exist; use a defined service.

Spec reference: https://tods-transit.org/spec/#vehicle_assignmentstxt

TODS-W313: Supplement deletes a row that is not in GTFS

Severity: WARNING. Needs a companion GTFS feed.

A supplement row sets TODS_delete=1 but no row with that primary key exists in the companion GTFS file. Nothing is deleted; this usually means the ID is wrong or the GTFS feed changed.

Example (stops_supplement.txt):

Before:

stop_id,TODS_delete
s2,1

After:

stop_id,TODS_delete
s1,1

s2 is not in the companion GTFS stops.txt, so there is nothing for this delete to remove; check for a typo against the stop_id it should target (here, s1).

Spec reference: https://tods-transit.org/spec/#supplement-files

TODS-E314: Supplement row references a GTFS entity that does not exist

Severity: ERROR. Needs a companion GTFS feed.

A supplement row names a route, service, trip, or stop that is not in the supplemented GTFS feed (for example, a trip added by trips_supplement.txt with a route_id that exists nowhere). The merged feed would not form valid GTFS.

Example (trips_supplement.txt):

Before:

route_id,service_id,trip_id
ghost,daily,t9

After:

route_id,service_id,trip_id
r1,daily,t9

route_id ghost is not defined in the companion GTFS routes.txt; reference a route that exists.

Spec reference: https://tods-transit.org/spec/#supplement-files

TODS-W315: Run event location does not match the trip's first or last stop

Severity: WARNING. Needs a companion GTFS feed.

A run event works a trip end to end (trip_id set, the matching mid_trip flag not 1), but its start_location is not the trip's first stop, or its end_location is not the trip's last stop, in the supplemented stop_times.txt.

Interpretation: the spec says these locations 'should' be the trip endpoints, so a mismatch is a warning; skipped for mid-trip events and for trips with no stop_times.

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,event_type,trip_id,start_location,start_time,end_location,end_time
weekday,1,10,Operator,T1,S3,09:00:00,S2,10:00:00

After:

service_id,run_id,event_sequence,event_type,trip_id,start_location,start_time,end_location,end_time
weekday,1,10,Operator,T1,S1,09:00:00,S2,10:00:00

stop_times.txt says trip T1's first stop is S1, not S3; the run event's start_location should match.

Spec reference: https://tods-transit.org/spec/#run_eventstxt

TODS-W316: Run event time does not match the trip's scheduled time

Severity: WARNING. Needs a companion GTFS feed.

A run event works a trip end to end (trip_id set, the matching mid_trip flag not 1), but its start_time is not the trip's first scheduled departure, or its end_time is not the trip's last scheduled arrival, in the supplemented stop_times.txt.

Interpretation: the companion of TODS-W315 for time: a run event claiming to work a whole trip should span the trip's scheduled times, so a mismatch is a warning; skipped for mid-trip events, for trips with no stop_times, and when either time is unparseable.

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,event_type,trip_id,start_location,start_time,end_location,end_time
weekday,1,10,Operator,T1,S1,08:30:00,S2,10:00:00

After:

service_id,run_id,event_sequence,event_type,trip_id,start_location,start_time,end_location,end_time
weekday,1,10,Operator,T1,S1,09:00:00,S2,10:00:00

stop_times.txt schedules trip T1 to depart S1 at 09:00:00; the run event's start_time should match within tolerance.

Spec reference: https://tods-transit.org/spec/#run_eventstxt

Semantic checks (TODS-x4xx)

TODS-E401: Event ends before it starts

Severity: ERROR.

A run event's end_time is earlier than its start_time. Equal times are fine (the spec allows zero-duration events such as a report time); for work past midnight, use hours of 24 or more rather than wrapping around.

Interpretation: the spec is silent on end<start; this treats it as an error and equal times as valid.

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,1,Report,garage,10:00:00,garage,09:00:00

After:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,1,Report,garage,09:00:00,garage,10:00:00

end_time (09:00:00) is before start_time (10:00:00); an event cannot end before it starts.

Spec reference: https://tods-transit.org/spec/#run_eventstxt

TODS-E402: Two trip events in one run overlap in time

Severity: ERROR.

Within one run, two events that both reference trips overlap in time. The spec prohibits this: an employee cannot be on two trips at once. Touching end-to-start (zero-minute overlap) is allowed.

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,event_type,trip_id,start_location,start_time,end_location,end_time
daily,1,1,Operator,t1,s1,10:00:00,s2,11:00:00
daily,1,2,Operator,t2,s2,10:30:00,s3,11:30:00

After:

service_id,run_id,event_sequence,event_type,trip_id,start_location,start_time,end_location,end_time
daily,1,1,Operator,t1,s1,10:00:00,s2,11:00:00
daily,1,2,Operator,t2,s2,11:00:00,s3,12:00:00

Event 2 starts (10:30:00) before event 1 ends (11:00:00); one run cannot be in two trips at once, so shift event 2 to start after event 1 ends.

Spec reference: https://tods-transit.org/spec/#event_sequence-and-event-times

TODS-W403: Event order disagrees with event times

Severity: WARNING.

Within one run, event_sequence does not increase with start_time. The spec says sequence values should increase throughout the day; out-of-order values usually mean the sequence or a time is wrong.

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,10,Report,garage,10:00:00,garage,10:05:00
daily,1,20,Report,garage,09:00:00,garage,09:05:00

After:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,10,Report,garage,09:00:00,garage,09:05:00
daily,1,20,Report,garage,10:00:00,garage,10:05:00

event_sequence 10 then 20 implies chronological order, but the times run backwards; reorder the rows (or the sequence numbers) to match the times.

Spec reference: https://tods-transit.org/spec/#event_sequence-and-event-times

TODS-W404: Employee is assigned to overlapping runs on the same date

Severity: WARNING.

An employee is assigned to two runs on the same date whose events overlap in time. Real schedules have legitimate exceptions, so this is a warning, not an error.

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,1,Work,s1,08:00:00,s1,12:00:00
daily,2,1,Work,s1,10:00:00,s1,14:00:00  # employee_run_dates.txt assigns emp-1 to both run 1 and run 2 on 20260106

After:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,1,Work,s1,08:00:00,s1,12:00:00
daily,2,1,Work,s1,10:00:00,s1,14:00:00  # employee_run_dates.txt assigns emp-1 to only one of run 1 / run 2 on 20260106

Run 1 (08:00-12:00) and run 2 (10:00-14:00) overlap; the same employee cannot work both on the same date.

Spec reference: https://tods-transit.org/spec/#employee_run_datestxt

TODS-E405: Run operates on dates its trip does not

Severity: ERROR. Needs a companion GTFS feed.

A run event works a trip whose service is different from the run's service, and the run's service operates on dates the trip's service does not. The spec requires the run's dates to be a subset of the trip's dates.

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,event_type,trip_id,start_location,start_time,end_location,end_time
weekday,1,1,Operator,t1,s1,08:00:00,s2,09:00:00  # trips.txt: t1 belongs to service_id weekend

After:

service_id,run_id,event_sequence,event_type,trip_id,start_location,start_time,end_location,end_time
weekday,1,1,Operator,t1,s1,08:00:00,s2,09:00:00  # trips.txt: t1 belongs to service_id weekday

This run's service_id (weekday) does not match the service_id of the trip (t1) it references in trips.txt; a run and the trips it runs must share a service.

Spec reference: https://tods-transit.org/spec/#service_id-crew-schedules-and-trip-schedules

TODS-W406: Employee assignment date is outside the run's service days

Severity: WARNING. Needs a companion GTFS feed.

An employee_run_dates.txt row assigns a run on a date when the run's service_id does not operate, according to the supplemented calendars.

Example (employee_run_dates.txt):

Before:

date,service_id,run_id,employee_id
20260110,weekday,1,emp-1  # calendar.txt: weekday does not operate 2026-01-10 (Saturday)

After:

date,service_id,run_id,employee_id
20260112,weekday,1,emp-1  # 2026-01-12 is a Monday, when weekday service runs

The assignment date must be a date the run's service actually operates, per calendar.txt/calendar_dates.txt.

Spec reference: https://tods-transit.org/spec/#employee_run_datestxt

TODS-W407: Vehicle assignment date is outside the service days

Severity: WARNING. Needs a companion GTFS feed.

A vehicle_assignments.txt row names a service_id and a date when that service does not operate, according to the supplemented calendars.

Example (vehicle_assignments.txt):

Before:

date,service_id,block_id,vehicle_id
20260110,weekday,B1,bus-1  # weekday service does not operate 2026-01-10 (Saturday)

After:

date,service_id,block_id,vehicle_id
20260112,weekday,B1,bus-1  # 2026-01-12 is a Monday, when weekday service runs

Same idea as TODS-W406, for vehicle assignments: the date must fall within the service's operating days.

Spec reference: https://tods-transit.org/spec/#vehicle_assignmentstxt

TODS-W408: Identical employee assignment appears twice

Severity: WARNING.

Compatibility signal for an exact duplicate in employee_run_dates.txt. TODS-E204 now reports the same row as a primary-key error; this warning is retained so existing machine consumers do not lose the earlier rule ID.

Example (employee_run_dates.txt):

Before:

date,service_id,run_id,employee_id
20260106,daily,1,emp-1
20260106,daily,1,emp-1

After:

date,service_id,run_id,employee_id
20260106,daily,1,emp-1

The two rows are identical; drop the duplicate (tods-validate fix does this automatically).

Spec reference: https://tods-transit.org/spec/#employee_run_datestxt

TODS-W409: Consecutive run events do not connect in space

Severity: WARNING.

Within one run, an event ends at one location but the next event in event_sequence order starts somewhere else. An operator is one person who cannot teleport, so a gap usually means a missing deadhead event or a wrong location. Events with a blank endpoint are skipped.

Interpretation: the spec does not state this explicitly, but a run is a continuous tour of duty; legitimate exceptions exist (so a warning), and adjacencies with a blank location are not flagged.

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,1,Pullout,garage,08:00:00,stopA,08:30:00
daily,1,2,Operate,stopB,08:30:00,garage,09:30:00

After:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,1,Pullout,garage,08:00:00,stopA,08:30:00
daily,1,2,Operate,stopA,08:30:00,garage,09:30:00

Event 1 ends at stopA but event 2 starts at stopB; consecutive events in a run should connect at the same location unless a mid-trip flag explains the gap.

Spec reference: https://tods-transit.org/spec/#event_sequence-and-event-times

Coverage (opt-in, informational) (TODS-x5xx)

TODS-I501: GTFS trips have no run event

Severity: INFO. Needs a companion GTFS feed. Opt-in: off by default, enable with --enable coverage or --enable TODS-I501.

Some trips in the companion GTFS feed are never referenced by a run event, so no crew work is described for them. This is informational: not every trip must appear in run_events.txt, but wide gaps can mean an incomplete export.

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,event_type,trip_id,start_location,start_time,end_location,end_time
daily,1,10,Operator,t1,s1,10:00:00,s2,10:30:00  # trips.txt also defines trip t2, with no run event referencing it

After:

service_id,run_id,event_sequence,event_type,trip_id,start_location,start_time,end_location,end_time
daily,1,10,Operator,t1,s1,10:00:00,s2,10:30:00
daily,1,20,Operator,t2,s2,10:30:00,s3,11:00:00

t2 has no run event at all. Informational coverage check; opt in with --enable coverage or --enable TODS-I501.

Spec reference: https://tods-transit.org/spec/#run_eventstxt

TODS-I502: Blocks have no vehicle assignment

Severity: INFO. Needs a companion GTFS feed. Opt-in: off by default, enable with --enable coverage or --enable TODS-I502.

Some blocks in the companion GTFS feed have no row in vehicle_assignments.txt, so no vehicle is assigned to operate them. Informational: vehicle assignments are optional, but unassigned blocks may signal an incomplete export.

Example (vehicle_assignments.txt):

Before:

date,service_id,block_id,vehicle_id
20260106,daily,B1,bus-1  # trips.txt also defines block B2, with no vehicle_assignments row

After:

date,service_id,block_id,vehicle_id
20260106,daily,B1,bus-1
20260106,daily,B2,bus-2

Block B2 has no vehicle assignment. Informational coverage check; opt in with --enable coverage or --enable TODS-I502.

Spec reference: https://tods-transit.org/spec/#vehicle_assignmentstxt

Advisory (opt-in) (TODS-x6xx)

TODS-I601: Run has a long span with no break event

Severity: INFO. Opt-in: off by default, enable with --enable advisory or --enable TODS-I601.

A run is on duty for a long continuous span with no event whose type names a break, lunch, or meal. Advisory only: break modelling varies by agency and labor agreement, so this is never an error.

Interpretation: advisory: 'break' detected by event_type containing break/lunch/meal

Example (run_events.txt):

Before:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,10,Operator,s1,06:00:00,s1,06:10:00
daily,1,20,Operator,s1,06:10:00,s1,14:00:00

After:

service_id,run_id,event_sequence,event_type,start_location,start_time,end_location,end_time
daily,1,10,Operator,s1,06:00:00,s1,06:10:00
daily,1,20,Operator,s1,06:10:00,s1,10:00:00
daily,1,25,Break,s1,10:00:00,s1,10:30:00
daily,1,30,Operator,s1,10:30:00,s1,14:00:00

Nearly 8 hours pass with no Break event. Advisory check; opt in with --enable advisory or --enable TODS-I601.

Spec reference: https://tods-transit.org/spec/#run_eventstxt