Skip to content

docs: document the LeRobot importer's episode/v1 keys in FORMAT.md - #410

Merged
kstonekuan merged 2 commits into
Hebbian-Robotics:mainfrom
alorentiar:docs/lerobot-episode-keys
Sep 5, 2026
Merged

docs: document the LeRobot importer's episode/v1 keys in FORMAT.md#410
kstonekuan merged 2 commits into
Hebbian-Robotics:mainfrom
alorentiar:docs/lerobot-episode-keys

Conversation

@alorentiar

Copy link
Copy Markdown
Contributor

Closes #409

What

docs/FORMAT.md documents episode/v1 as five named keys plus "(any user
key)". The LeRobot importer actually writes eleven: task, operator,
embodiment, success, plus seven importer-only keys that the table does not
mention.

Why

Six of the undocumented keys — source_dataset, source_revision,
source_episode_index, converter_version, camera_keys, and gop_seconds
are load-bearing: _episode_identity_matches reads them back to decide whether
an already-published landing file can be reused instead of reconverted. A
reader who sees "any user key passes through untouched" could reasonably
conclude these are free-form, and break the resume contract without meaning to.

success_derivation is the key a data consumer actually needs: it names the
methodology behind success (max(stats/next.success): any success frame
makes the episode a success). Both keys are absent together when the source
declares no outcome feature.

gop_seconds also appears in provenance/v1; for an imported episode both
records carry the same value, and the episode copy exists so the resume check
can compare the keyframe interval without opening the transform's record. The
new prose says so explicitly rather than duplicating the row silently.

Changes

  • Add the seven importer-written keys to the episode/v1 table, with enough
    detail to reproduce each value's format (camera_keys is a compact JSON
    array of strings, gop_seconds is %g-formatted, converter_version is
    currently lerobot-converter-v7).
  • Explain which keys the LeRobot importer writes (as opposed to a recorder),
    that six of them are a contract with the importer's resume path rather than
    free-form user keys, and how success/success_derivation relate.

Markdown only — no source or test changes.

Validation

lychee --no-progress --include-fragments \
  --exclude '^https://github\.com/Hebbian-Robotics/hflow/(issues|security/advisories/new)$' \
  --exclude-path references/mcap-spec.md \
  --exclude-path references/foxglove-CompressedVideo.proto .
# 378 Total · 374 OK · 0 Errors · 4 Excluded

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown

👋 Hi @alorentiar — thank you so much for your first contribution to HFlow!

A maintainer will review your pull request as soon as possible. In the meantime:

💡 Tip: one open pull request per contributor at a time. Issues with an assignee are taken; everything else is fair game.

We are excited to have you here and appreciate your help making the project better! 🙌

The importer keys sat below *(any user key)*, which reads as a catch-all,
so specific keys after it look like a kind of user key: the opposite of
what the surrounding prose says. Moved above it, and the prose now names
the first key instead of referring to a position.

Em dashes are not used in this repo's prose.

@kstonekuan kstonekuan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, merging. Welcome, and this is a strong first PR.

You did the thing the issue was really asking for, which was not "list the keys" but "explain what they are for". Every format claim checks out against the source:

camera_keys           json.dumps(..., separators=(",", ":"))   compact JSON array   lerobot.py:138
gop_seconds           f"{IMPORT_GOP_SECONDS:g}"                %g-formatted         lerobot.py:1239
source_episode_index  str(episode_index)                       decimal string       lerobot.py:1236

And the six-key resume contract is exactly the six _episode_identity_matches compares at lerobot.py:186-193, which is the part a reader most needs and the part that was easiest to get subtly wrong.

The gop_seconds paragraph is the best thing here. Documenting why the same key appears in two records, rather than documenting it twice and leaving a reader to wonder which is authoritative, is the harder and more useful choice.

I pushed one fixup, 2e26b31, both parts cosmetic. The new rows sat below the *(any user key)* row, which is a catch-all, so specific keys after it read as a kind of user key: precisely the opposite of what your prose then says. Moving them above it lets the catch-all stay last where it belongs, and the prose now names the first key rather than pointing at a position, so it survives the next key being added. I also dropped the em dashes; this repo's prose does not use them, which is a house style thing you had no way to know.

One judgment call I made rather than asked about: I changed converter_version's description from "currently lerobot-converter-v7" to the form lerobot-converter-vN. The value was accurate this morning and moved twice today (v6 in #390, v7 in #403), and a version pinned in prose that nothing tests is exactly the kind of thing that quietly goes stale. Saying the shape rather than the current value keeps it true.

Gate on the merged result: link check 378 links, 374 OK, 0 errors; ruff check, ruff format --check, ty check clean, 1531 passed / 6 skipped.

Closes #409. If you want another, there are three more starter issues open right now: https://github.com/Hebbian-Robotics/hflow/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22

Two tips that will save you time on a second PR, and neither is a criticism of this one. Only an assignee reserves an issue, so everything unassigned is fair game and a linked PR does not block you. And we cap non-collaborators at one open PR at a time, so a bot will politely close a second and invite you back once this one lands.

@kstonekuan
kstonekuan merged commit 224dc6f into Hebbian-Robotics:main Sep 5, 2026
6 checks passed
@chiruu12

chiruu12 commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Flagging a line in this PR that looks unintended: it changes the max_retries type guard in src/hflow/build_ai_vlm_checks.py to if False:, which is on main now. Details and the behaviour it lets through are in #413.

@alorentiar

Copy link
Copy Markdown
Contributor Author

Thanks for flagging this, that line should not be there. I traced where it came from: my commit on the branch only touched docs/FORMAT.md, and the guard change arrived in a later commit (2e26b31) that was pushed after mine. I restored the guard and added a regression test for it in #414.

kstonekuan added a commit that referenced this pull request Sep 5, 2026
* fix(checks): restore the max_retries type guard

The guard went out disabled with #410, so bools and floats were accepted
as max_retries. Restore the isinstance check and add a regression test
covering True and 2.5, both of which slipped through while it was off.

* test(build-ai): split the max_retries cases so ty can read them

The shared **kwargs dict inferred as dict[str, str], so splatting it into
endpoint, model and max_retries produced seven ty errors. Parametrized
instead, with the positive case as its own test, and ty's own suppression
comment rather than the mypy-style one, which ty does not honour.

---------

Co-authored-by: Kingston <kingston@hebbianrobotics.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FORMAT.md documents five episode/v1 keys; the LeRobot importer writes eleven, and five of the undocumented ones gate import resume

3 participants