Metadata-Version: 2.4
Name: stamplint
Version: 0.2.0
Summary: timestamp sanity linter for robot bag files
License-Expression: Apache-2.0
Project-URL: Repository, https://github.com/sa1ntsinner/stampdoctor
Keywords: ros,ros2,rosbag,mcap,timestamp,ptp,clock,robotics
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Developers
Classifier: Topic :: Scientific/Engineering
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: rosbags<0.12,>=0.11.4
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Dynamic: license-file

# stamplint

stamplint reads a ROS 1 or ROS 2 recording and reports what is wrong with the timestamps in it: stamps that sit a leap second offset away from the receiving clock, stamps that go backwards, stamps that freeze, stamps of zero, dropouts, and clocks that drift apart. It then collapses the findings into a short verdict that names the probable cause instead of listing symptoms per topic.

It is pure Python and does not need a ROS installation. Bags are read through `rosbags`, and stamps are taken straight from the serialized bytes; only the first message of each topic is deserialized, to validate the parser against it.

It ships with `bagmutate`, which writes a copy of a bag with one known timestamp fault injected, so every check has a positive control.

## Usage

```
pip install stamplint

stamplint /path/to/bag
stamplint /path/to/bag --topics /scan --topics /imu --limit 5000
stamplint /path/to/bag --stats
stamplint /path/to/bag --json-verdict

bagmutate clean.bag out --pathology tai
```

Exit code is `0` when no error finding was raised, `1` when at least one was, and `2` on bad usage or a bag that could not be read.

## Public API

Other packages import these names from `stamplint` itself. They are the supported surface and do not change without a minor release; everything else in the package is internal.

| name | what it is |
| --- | --- |
| `stamp_from_cdr(raw)` | header stamp in seconds, read from a serialized CDR message |
| `cdr_stamp_parts(raw)` | the same stamp as `(sec, nanosec)` |
| `classify_offset(topic, offset, stamps)` | grades one median offset as `(class, severity, message)` |
| `largest_backward_step(stamps)` | biggest backward jump as `(seconds, index)` |
| `longest_frozen_run(stamps, receive_times)` | longest qualifying frozen run, or `None` |
| `starts_with_header(reader, connection)` | whether a bag connection type leads with a `std_msgs/msg/Header` |
| `probe_stamp_parser(reader, connection, raw)` | whether the raw parser agrees with the deserialized stamp |
| `UnsupportedEncapsulation` | raised by the parser for an encapsulation it refuses, by name |
| `MAX_PLAUSIBLE_LATENCY_S`, `FROZEN_MIN_RUN`, `FROZEN_MIN_SPAN_S` | thresholds shared with live grading |

## More

Full documentation, the live ROS 2 monitoring node and a catalog of the real world failures behind each check: https://github.com/sa1ntsinner/stampdoctor

Licensed under Apache 2.0.
