Repository navigation
Conversation
RyanPCo
left a comment
There was a problem hiding this comment.
Automated adversarial review (read-only; findings were checked by a second skeptical pass before posting): 3 medium, 3 low, 11 nit.
| SHORT_SIDE = 360 | ||
| IDENTITY_POSE = np.array([0, 0, 0, 1, 0, 0, 0], dtype=np.float32) | ||
| REQUIRED = ("lab", "task_name", "operator") | ||
| PLACEHOLDERS = {"", "none", "null", "nan", "unknown", "debug"} |
There was a problem hiding this comment.
medium (duplication): PLACEHOLDERS is a smaller copy of required_metadata._PLACEHOLDER_VALUES, so a lab, operator or task_name of 'n/a', 'tbd' or '-' gets through here even though ZarrWriter and the validators reject it. Drop PLACEHOLDERS and have _placeholder return _text(v) is None or is_placeholder(str(v)), using egomimic.rldb.zarr.required_metadata.is_placeholder.
| def detect_format(attrs: dict, keys: set[str]) -> str: | ||
| """The FORMATS entry of the converter that wrote the episode; fails on unknown ones.""" | ||
| emb = str(attrs.get("embodiment", "")).lower() | ||
| kind = emb.split("_")[0] |
There was a problem hiding this comment.
medium (correctness): Vendor-tagged embodiments are rejected. detect_format splits the raw name, so MECKA_BIMANUAL and SCALE_LEFT_ARM zarrs from the vendor-split registry raise NotImplementedError. ARIA_* passes detection here but then fails in steps_schema at line 446, and the raw name is also what ends up in meta["embodiment"]. Normalize once with canonical_embodiment_name(attrs["embodiment"]).lower() and use that for detection, arm layout, schema and meta. Add a test with a MECKA_BIMANUAL zarr.
| out = commit.commit_annotations( | ||
| lance_root, | ||
| rv.adds, | ||
| [], |
There was a problem hiding this comment.
medium (data-integrity): With --replace, annotations the earlier delivery committed for a recording are never removed. commit.replace rewrites steps and the catalog but not annotations.lance, and annotation_id hashes the content. If a re-conversion moves a span (a new clock, clamping or text), the old row stays beside the new one and may fall outside the replaced task bounds. For recordings in result["replaced"], delete the committed annotation_ids for that recording and annotation_vendor that are missing from the new set. If keeping them is intended, document it.
| SENTINEL = 1e8 | ||
| SHORT_SIDE = 360 | ||
| IDENTITY_POSE = np.array([0, 0, 0, 1, 0, 0, 0], dtype=np.float32) | ||
| REQUIRED = ("lab", "task_name", "operator") |
There was a problem hiding this comment.
low (duplication): REQUIRED here and lance_commit.REQUIRED_META are two more literal copies of the unwaivable fields, which mcap/spec.py already derives as UNWAIVABLE_FIELDS from REQUIRED_METADATA_FIELDS and WAIVABLE_FIELDS. Move UNWAIVABLE_FIELDS into rldb/zarr/required_metadata.py and import it in spec.py, zarr_to_lance and lance_commit, so a change to the rule cannot leave one copy behind.
| def episode_metadata(attrs: dict, metadata: dict | None) -> dict: | ||
| """Zarr attrs overlaid with `metadata`; rejects missing or placeholder lab/task_name/operator.""" | ||
| m = {k: attrs.get(k) for k in ("task_name", "task_description", "scene", "objects")} | ||
| over = {k: v for k, v in (metadata or {}).items() if _text(v) is not None} |
There was a problem hiding this comment.
low (correctness): Blank manifest cells override real zarr attrs. csv.DictReader returns '' for an empty or NULL cell, and _text('') is not None, so task='' becomes task_name='' and the episode is rejected even when the zarr has a task_name. A blank task_description likewise replaces the zarr's. Drop empty or placeholder values from the overlay, for example with if not _placeholder(v).
| worst[key] = f"shape {tuple(v.shape)} vs {tuple(w.shape)}" | ||
| continue | ||
| d = (v.float() - w.float()).abs() | ||
| if "images" in key: |
There was a problem hiding this comment.
nit (simplification): Both branches set worst[key] the same way. Write if 'images' in key: img.append(float(d.mean())) and put a single worst[key] = max(...) after it.
| ap.add_argument("--samples", type=int, default=200) | ||
| args = ap.parse_args() | ||
| (name,) = [p.name for p in args.zarr_dir.iterdir()] | ||
| h = name[: -len(".zarr")] if name.endswith(".zarr") else name |
There was a problem hiding this comment.
nit (duplication): This line repeats zarr_to_lance.episode_hash_of. Add it to the existing import and write h = episode_hash_of(name).
|
|
||
|
|
||
| def _dexmate(): | ||
| # No Dexmate embodiment class on this branch: every numeric column, untransformed. |
There was a problem hiding this comment.
nit (stale-comment): 'on this branch' will read wrong after merge. Reword to 'No Dexmate embodiment class yet: every numeric column, untransformed.'
| if fmt == "microagi_v2": | ||
| assert task["objects"] == ["iron"] | ||
| videos = set(dict(rec["video_path"])) | ||
| assert {f"{c}" for c in spec.get("cams", ("front_1",))} <= videos |
There was a problem hiding this comment.
nit (test-quality): {f"{c}" for c in spec.get('cams', ('front_1',))} is just set(spec.get('cams', ('front_1',))). At line 274 the identity-pose literal could be zarr_to_lance.IDENTITY_POSE, or a one-line list that black keeps on one line.
| For the vendor and robot zarrs that have no raw converter (FORMATS); Aria and EVA migrate | ||
| from raw (aria_to_lance, eva_to_lance), so their zarrs are refused. Steps rows are exactly | ||
| the zarr frames: the zarr converters already deleted the frames they could not use | ||
| (untracked hands, missing poses), so nothing is filled back in and a gap in `timestamp_ns` |
There was a problem hiding this comment.
nit (correctness): "a gap in timestamp_ns is where zarr dropped frames" is true only for zarrs with obs_rgb_timestamps_ns. For mecka, scale, yam and dexmate the clock is start + i/fps over the surviving frames, so dropped frames leave no gap and gaps is always 0. Narrow the docstring, and consider recording in meta that the clock is synthetic.
eab64d3 to
d5864a2
Compare
60d159f to
73bd06a
Compare
|
Review follow-up (force-pushed). All 17 findings fixed:
|
zarr_to_lance converts one zarr episode (mecka, scale, microagi v2, yam, dexmate) into a
delivery: steps rows are exactly the zarr frames, validity flags mark sentinels, untracked
hands and zero robot poses, and the JPEGs are re-encoded as AV1 MP4s. The recording id is
recording_id("zarr", episode_hash). Vendor-prefixed embodiments (MECKA_BIMANUAL) map onto
human_*. lab, task_name and operator come from the SQL row passed as metadata and are never
waived; a blank or placeholder metadata value falls back to the zarr attr. Aria and EVA
zarrs are refused: they migrate from raw. Without per-frame times the clock is start +
i / fps, which meta.json's provenance records as clock "fps".
The zarr's annotations array is carried in meta.json on the recording clock (frame i is
steps row i, so episodes without obs_rgb_timestamps_ns map by index), and lance_commit
commits a batch's annotations as one annotation change right after the batch. Replacing a
recording deletes its committed annotations from the delivery's vendors that the new
delivery no longer carries.
lance_commit gains the zarr source, sharing load_meta_deliveries with EVA; a zarr delivery
may have no capture time. rldb/lance/metadata.py holds the value helpers (text_or_none,
placeholder, objects_list, read_manifest) the converters and committer share, and
required_metadata.UNWAIVABLE_FIELDS the always-required fields. check_zarr_to_lance compares
a converted episode with its zarr: steps values, decoded video PSNR/SSIM, and loader
samples under the format's training config.
Claude-Session: https://claude.ai/code/session_01HjCQBqQCr2igFEMR7yUovw
73bd06a to
a03459a
Compare
d5864a2 to
853c113
Compare
Converts the vendor and robot zarr episodes that have no raw converter into committer
deliveries, so the migration can move them into Lance. Aria and EVA migrate from raw
(aria_to_lance, eva_to_lance), so their zarrs are refused here; the aria/eva-zarr path and
the aria parity configs from the prototype are gone.
egomimic/scripts/zarr_to_lance.py,
convert_zarr_episode(zarr, out_dir, metadata):dexmate (DEXMATE_STEPS, tactile images as extra videos), detected from the zarr attrs
and keys. Microagi v1, trace, aria and eva fail with a clear NotImplementedError.
sentinel values, untracked (all-zero) hands and zero robot poses (forward-filled as
eva_to_zarr does). Timestamps are obs_rgb_timestamps_ns, else the hash's start + i/fps.
front_1_<short>streamfor human front cameras; intrinsics are scaled to match.
canonical_embodiment_name.
recording_id("zarr", episode_hash), not keyed by lab. lab, task_name and operator comefrom
metadata(the SQL row) over the zarr attrs and are never waived; a blank orplaceholder metadata value (required_metadata.is_placeholder) falls back to the zarr
attr; scene may be null. Without per-frame times, meta.json provenance says clock "fps".
annotationsarray is where vendor language spans live (checked onmecka, scale, microagi v2, sharpa_dex and yam episodes; SQL
segmentsis only filled forsome mecka rows and matched the zarr). Spans are mapped onto the recording clock (frame i
is steps row i, so episodes without obs_rgb_timestamps_ns map by index; an end past the
last frame is clamped, as yam writes them) and written to meta.json
annotations.lance_commit:
--source zarrsharesload_meta_deliverieswith EVA; a zarr delivery may have nocapture time (abc's UUID hashes).
file and committed as one annotation change (annotation_vendor = lab). A span that fails
review is reported, never the recording. Lance training samples over task segments
(rldb/lance: one leaf per recording, sampled over its task segments #722), so this keeps vendor spans usable after the migration. With
--replace, areplaced recording's committed spans from the delivery's vendors that the new delivery
no longer carries are deleted.
egomimic/rldb/lance/metadata.pyholds the value helpers the converters, planner andcommitter share (text_or_none, placeholder, objects_list, read_manifest), and
required_metadata.UNWAIVABLE_FIELDSthe always-required fields.egomimic/scripts/lance_pilot/check_zarr_to_lance.py compares a converted episode with its
zarr: steps values on valid frames, decoded-video PSNR/SSIM, and loader samples under the
format's training keymap and transforms.
Testing: on a compute node, tests/unit/test_zarr_to_lance.py (new: a human zarr with
dropped frames and sentinels committed end to end, one-arm embodiments, required metadata,
unknown and aria zarrs refused, a round trip per vendor/robot format against the
ZarrDataset twin, robot zero-pose dropout, untracked hands, annotations committed on the
recording clock with and without per-frame times) with test_lance_committer and
test_lance_annotations: 36 passed.
🤖 Generated with Claude Code
https://claude.ai/code/session_01HjCQBqQCr2igFEMR7yUovw