Robot Dataset Audits / ledger

← Ledger · Entry 01

FineART: structurally clean, semantically unmeasured

Six sampled episodes of Scale AI × Hugging Face's 1,718-hour bimanual dataset pass every structural check available. The dataset's distinguishing feature — 533,913 dense subtask labels — is not reachable by any metric in current tooling. The default configuration of the audit tool also rejects 83% of legitimate episodes. Both statements are measurements.

Dataset
lerobot/FineART — co-released by Scale AI and Hugging Face LeRobot
Scale
40,543 episodes · 185,534,500 frames · 1,718 hours · 151 tasks
Format
LeRobot dataset v3.0 · robot_type: aloha · Trossen Stationary AI
Sample
6 episodes (index 0–5) · 13,949 frames · 0.015% of the corpus
Tool
robot-data-audit 0.12.1, installed from PyPI (not the source tree)
Environment
Python 3.13 · av 19.0.2 · OpenCV 4.14.0 — video layer active, not degraded
Audited
2026-11-02
Update — 2026-11-03 · fixed in 0.12.2

Section 04 documents a false positive in video_freeze as measured on 0.12.1. That was a defect in the tool, not a property of the dataset, and it is fixed in 0.12.2. The criterion changed in kind: from “the frame difference is small” — an absolute epsilon, max(0.10, 0.25 × p10), which in a fixed overhead view sits inside the normal distribution — to “the camera re-sent the previous frame”, a duplicate epsilon bounded above by half the stream’s own 25th percentile.

Re-running this exact 6-episode subset on the published 0.12.2 wheel returns 6/6 PASS, zero flagged regions, exit 0 (raw output). Section 04 is kept as written: it is the record of what 0.12.1 did to this data, and it is the reason the criterion exists in its current form.

Verdict

pass with caveats

On the dataset: no structural defect found. Six of six sampled episodes pass schema conformance, invalid-value, timestamp, dropout, and video-frame-integrity checks. The v3.0 shared-MP4 slicing logic reads correctly, including per-camera from_timestamp / to_timestamp offsets.

On the tooling: two failures. Default rda audit excludes 5 of 6 episodes on a freeze-detector false positive, and the entire annotation layer — the reason this dataset exists — has zero metric coverage. The first is fixed in 0.12.2 (see the note above); the second is not, and is the more consequential of the two.

Caveat on scope: six episodes is enough to characterise format handling and mechanism, not the full-corpus defect distribution. Nothing here should be read as a statement about all 40,543 episodes.

01What was audited

FineART is a bimanual manipulation corpus recorded on a Trossen Stationary AI system with ALOHA2 grippers: four cameras at 360×640 and 30 fps, 14-dimensional joint-plus-gripper state and action, roughly 1.86 TB on the Hub. The property that separates it from other open bimanual datasets is annotation density: 533,913 human-written subtask segments, about 13 per episode, covering the full recorded duration rather than a filtered subset.

The sample is the first six episodes of data/chunk-000/file-000.parquet (116 MB) plus the 24 corresponding MP4s, four cameras per episode (≈130 MB). The subset was materialised as a standalone dataset directory with info.json rewritten to the subset's true total_episodes and total_frames, so that episode-count checks would be evaluated against real values rather than the full corpus.

All six episodes are drawn from a single task family (pick-and-place of candle holders). That is deliberate — it tests whether format handling works — and it is also the reason no distributional claim is made below.

02Structural layer: no defect found

CheckResultNote
missing_dropout6/6 passNo gaps in frame_index or timestamp
invalid_values6/6 passNo NaN or Inf in state or action
schema_consistency6/6 passDtypes and shapes stable across episodes
timestamp_validity6/6 passMonotonic, no duplicates
video_frame_integrity6/6 passDecoded frame counts match v3.0 slice metadata
video_stream_presence6/6 passAll four cameras present in every episode
video_timestamp_alignment6/6 passA/V offset within tolerance
video_stream_span, offset, driftmeasuredComputed, not UNDETERMINED
pii_scanclean19 text surfaces scanned, zero findings
joint_limitN/Ajoint_limits_not_provided — see §05
sensor_synchronizationN/A“no stream timestamps” — see §05

One diagnostic surfaced that is worth flagging to the training side rather than as a defect: action_discontinuity reported 108 discontinuities across 5 episodes. With 30 fps teleoperation and 50 Hz control, single-frame action jumps are expected at grasp and release events; the count is consistent with that reading. It is recorded here because it is the one structural signal that is non-zero, not because it indicates damage.

03Verifying that detection works at all

A clean result is only meaningful if the checker can fail. To test that, two defects were injected into a copy of the subset and the audit re-run:

EpisodeInjected defectVerdictReason emitted
0, 1, 2, 5nonePASS—
310 NaN framesEXCLUDEinvalid_values (L1): 10 NaN + 0 Inf values
450 frames removedEXCLUDEmissing_dropout (L1): 50 missing frame(s)

Both defects were caught, attributed to the correct episode, and reported with the exact count. The four untouched episodes stayed clean. Detection works. The failures below are failures of default sensitivity and of coverage, not of mechanism.

04Default configuration rejects 83% of legitimate episodes

Run with defaults, the audit excludes five of six episodes on a single rule, video_freeze_while_moving. Run with the motion source switched to the state stream, the same data yields zero exclusions.

InvocationPassReviewExcludeExitWall time
rda audit <subset> (default, action)0152292 s
--freeze-motion-source state0600298 s
--no-video60001.8 s

Independent re-measurement

The tool's verdict was not accepted. All 36 flagged regions were decoded again at full resolution with an independent script, and per-frame mean absolute difference was computed in grayscale — first at the tool's working resolution (64×64), then at source resolution.

ObservationMeasured
Flagged regions by cameracam_high 30 · cam_low 6 · cam_left_wrist 0 · cam_right_wrist 0
Full-resolution frame difference inside flagged regions0.10 – 0.15
Median frame difference, same camera, same episode0.29 – 0.87
Ratio (region / episode median)0.08 – 0.44
Regions with motion below 10% of episode median (approaching genuine freeze)3 / 36 — all in cam_low, episode 5

The picture is moving in all 36 regions. It is moving little: a bird's-eye camera over a 640×360 frame in which the robot occupies a small fraction of the sensor. Downsampled to 64×64 grayscale, with a fixed epsilon floor of 0.10 on frame difference, that motion approaches the noise floor. The motion gate, meanwhile, is driven by the action stream, which at 30 fps is essentially never still. “Action is moving” plus “pixels are barely changing” is then scored as a frozen camera, i.e. corrupt video.

Fact vs inference

Measured: the 36 flagged regions contain real, continuous pixel change; the exclusion verdicts are false positives; switching the motion source to state removes them without masking any true defect in this sample.

Inference, unverified: this is a pattern of fixed-elevation cameras combined with downsampling and a fixed epsilon, so other ALOHA-family datasets with a bird's-eye camera will likely reproduce it. No second dataset has been audited yet; the claim stays unverified until one is.

Practical consequence: the default invocation cannot be used as an acceptance gate on this dataset. It rejects 83% of valid episodes and returns exit code 2. Either pass --freeze-motion-source state, or whitelist the two static cameras, or make epsilon adaptive per camera — none of which is currently reachable from the CLI without editing code.

05Coverage gap: what the audit cannot see

This section is about the tool, not the dataset. Each row is a property FineART has and current tooling has no metric for — recorded so that a clean verdict is not mistaken for full coverage.

FineART propertyTooling statusCause
533,913 subtask labels (language_persistent) no metric Columns match neither observation.* nor action, so they are dropped in _extract_episode_from_dataframe
language_events no metric Same path; not read at all
Episode-level summary (success, execution quality) no metric No success-rate check exists in the metric set
joint_limit — the only physical hard gate N/A Read solely from info.json: joint_limits, which FineART omits; no Trossen or ALOHA platform profile exists in the tool
Per-camera from_timestamp / to_timestamp N/A sensor_synchronization reports “no stream timestamps” although the episode metadata carries them
Free text inside annotations not scanned pii_scan iterates episode metadata and feature names only
robot_type: aloha misreported Rendered as unknown in the acceptance summary

The joint_limit row matters more than it looks. It is the only check in the entire tool that asserts a physical constraint on the data; on FineART it is silently inapplicable because the dataset does not declare joint limits and the tool has no profile for this robot.

06The annotation layer, measured by hand

Because no metric covers it, a standalone script was written to characterise the subtask timeline. Scope: all 242 episodes in data/chunk-000/file-000.parquet, 2,108 subtask segments. This is a larger sample than the audit run and covers a wider task range.

PropertyResultReading
Segment count vs meta.subtask_count2,108 = 2,108Zero mismatches across 242 episodes
Timestamp monotonicity, non-overlappingcleanZero violations
Empty annotation textzeroNo blank segments
First segment start timemean 2.79 sp90 5.19 s, max 14.10 s; 235 of 242 episodes start later than 1 s
Last segment vs episode endby designp50 gap 8.80 s — the card defines the final segment as running to episode end; episode 0's last segment is Return to Home Position, which accounts for it
Largest gap between adjacent segmentsp50 22.85 sp99 60.73 s, max 92.80 s
language_eventsempty242 of 242 episodes

The annotation is internally consistent: counts agree with metadata, timestamps never invert, nothing is blank. The one number that has operational consequences is the leading gap. The dataset card describes roughly the first two seconds as having no active subtask; the measured median is 2.20 s, which matches. But the tail is longer than the median suggests — 11% of episodes start later than 5 s, the maximum is 14.10 s, and in 235 of 242 episodes the gap exceeds one second.

For a loader that resolves the active subtask by “most recent segment at or before t”, frames before the first segment have no answer. That branch is not an edge case; it fires in essentially every episode. This is a property of the data layout, not a defect, and it must be handled explicitly rather than discovered at training time.

07Cost at full scale

ModeMeasuredExtrapolated to 40,543 episodes
With video layer49 s/episode≈ 550 h single-process (≈ 23 days)
--no-video1.8 s / 6 episodeshours — bound by 23 GB of parquet
Peak memory≈ 0.9 GBSafe: data is sharded at 100 MB per file

The CLI exposes no concurrency. A full video-layer pass is therefore not a single command but a sharded job: split by chunk, run in parallel, aggregate the JSON. The parquet layer is cheap enough to run whole.

08Reproduction

# install (video layer needs av + opencv)
pip install robot-data-audit[parquet] "av>=12" "opencv-python-headless"

# structural pass only — fast, whole corpus is feasible
rda audit /data/FineART --no-video --format json -o fineart_novideo.json

# video layer on a shard — 0.12.1 only: the state stream was needed to suppress the false positive
rda audit /data/FineART_fold0 --freeze-motion-source state --format json -o fold0.json

# video layer, 0.12.2 criterion — the re-run quoted in the note at the top of this entry
rda audit /data/FineART_fold0 --format json -o fold0_0122.json

# render a shareable report
python tools/rda_render.py fold0.json --html report.html --badge badge.svg

Reading discipline: a clean --no-video run says nothing about the video layer. On 0.12.1 the video layer had to be run with --freeze-motion-source state on FineART, or it would exclude most of the corpus — that was a defect in the freeze criterion, not a property of the data. From 0.12.2 the default criterion is correct here and the flag is no longer needed.

09Corrections

Correction — 2026-11-03

An earlier version of this entry reported the trailing gap between the last subtask and the end of the episode (median 8.80 s) as an uncovered region. That was wrong. The dataset card defines the last segment as running to the end of the episode, and episode 0's final segment is Return to Home Position — 8.7 s of homing motion, correctly labelled. The finding was a misreading of the annotation protocol, not a defect in the data. It is kept here rather than deleted, because the failure mode it represents — reading a layout convention as a data error — is the one this ledger is most likely to repeat.

10Evidence files

Raw output from the runs described above, kept unedited so that any number in this entry can be traced back to the file that produced it.

FileContents
rda_fineart_default.jsonFull default run — 5 EXCLUDE, exit code 2
rda_report_fineart_default.htmlSingle-file shareable report
rda_report_injected_defects.jsonDefect-injection run — 2 EXCLUDE / 4 PASS
freeze_crosscheck.logFull-resolution re-measurement of all 36 flagged regions
subtask_probe.logAnnotation-layer probe — 242 episodes, 2,108 segments
rda_fineart_0.12.2.jsonSame 6 episodes on 0.12.2 — 6 PASS, 0 flagged regions, exit 0; per-camera motion profile in details.stream_motion_profile