feat(verify): check LeRobot prepared-manifest deliveries against receipts - #454
Conversation
Sagar-024
left a comment
There was a problem hiding this comment.
Approved. The part I like most is exit_code_for: 0, 1, and 3 live in one function, 2 is raised for unreadable input before a report exists, and FORMAT.md documents the split so CI can tell an unverifiable delivery from a damaged one. That split is easy to get wrong per command.
Checked against what the #432 contract needs: VerificationReport with .ok and .findings, each finding carrying .uri, .reason, and .detail, and the module importing from catalog and storage only, never from snapshot.py or lerobot.py. Extras ignored, nothing rewritten, nothing re-converted. Holds.
One coordination note for the snapshot verifier (#428): it will consume these same types, so its reasons need to live beside REASON_MISSING and friends rather than inventing a second vocabulary, and once two verifiers share this module it may be worth separating the shared types from the per-delivery verifiers. Neither blocks this PR.
|
Thanks @Sagar-024 , agreed on both notes for #428. I'll keep snapshot reason strings beside the existing CI is green here; ready for maintainer merge whenever @kstonekuan has a slot. |
|
@kstonekuan Fixed: episodes resolve as |
Sagar-024
left a comment
There was a problem hiding this comment.
Re-reviewed the fix commit (25a69e3). Stale approval replaced, this still holds the #432 contract checklist:
- CLI verb:
hflow verify lerobot-import <root>present. - Report:
.okderived from status, findings in one list, no raise on first mismatch. - Per-finding
uri/reason/detail: present, reasons from the shared constants. - Shared types: single
hflow.verificationmodule, no verifier-local report shapes. - Exit codes: 0 clean, 1 damaged, 2 unreadable input (raises), 3 unverifiable, via
exit_code_for. - Extras ignored: unlisted files under
landing/produce no finding.
The fix itself, verified in a scratch worktree (test_verification.py: 12 passed):
- Episodes now resolve as
landing/<basename>under the root being verified; the receipt uri is provenance, never a lookup path. - Both directions are pinned by mutation: mutating only the original keeps the copy green, damaging only the copy goes red.
- The deleted-original case and the bucket-root case are covered, plus the empty-claim receipt flipping to clean (the right call: nothing claimed, nothing damaged).
- Publish-time absolute uris still parse after a copy, so no schema bump is needed.
One note, non-blocking: .zcode shows a stray pr454.diff in my scratch from the review run; it is mine, not part of the PR.
Re-approving on the fix commit.
|
@VARUN3WARE Kingston unblocked the order, so I am landing #428 first with your type shape verbatim: VerificationStatus, VerificationFinding, VerificationReport with the ok property, your three REASON constants and exit_code_for, plus one REASON_NO_RECEIPT beside yours, hyphenated to match your convention. When you rebase #454, drop your copy of verification.py and import from the landed one. Your fix stays in the import-verifier half (the landing resolution and the empty-claim case), so nothing is lost. Ping me after the rebase and I will review again. |
|
@kstonekuan carried into #428: the moved-root test exports a snapshot to one root, copies it to a second, deletes the first entirely, then verifies the copy clean and then damaged, plus a variant where the original stays alive and clean while the copy is damaged, so damage is never masked by the export root. PR #457 is up with it, and the shared types land in VARUN's exact shape so #454 re-lands as an importer. |
|
@Sagar-024 Thanks for the re-review. Ack on order: once #457 lands I’ll rebase #454, import the shared types from your |
|
Fix confirmed with the same probe that caught it. Before, the third line read The third line is the one that mattered: damage in the copy is found even with an intact original sitting next to it, so the verifier is reading what it was handed. The fourth is my probe still holding the damaged copy from the step before, so All four cases from the review are in, and You also changed Not approving yet only because main moved underneath you: #457 merged and landed When you do it: take the merged module as the base and add to it rather than reconciling two copies. The basename mapping is worth one line in the PR body when you push: it means the verifier and the importer share the landing layout without the manifest recording it. That is fine, and it is the sort of coupling that should be stated rather than discovered. Ping me when it is clean and I will merge. |
Import VerificationReport from the landed verification module (Hebbian-Robotics#457) and keep the import-delivery half in lerobot_verify: resolve landing/<basename> under the verified root, treat empty episodes as ok, and cover Kevin's copy cases.
25a69e3 to
771aa6a
Compare
|
@kstonekuan Rebased onto main after #457. Dropped our duplicate |
kstonekuan
left a comment
There was a problem hiding this comment.
Clean rebase. The verifier moved to src/hflow/importers/lerobot_verify.py, the shared types are imported rather than reconciled, and the only edit to verification.py is a docstring now naming both concrete verifiers. That is the right shape: one contract, two implementations, neither owning the other.
Validated on the rebased branch: full gate clean, 1632 passed / 6 skipped. The path fix stays fixed, which I checked with the probe from the first round rather than trusting the rebase.
Merging. Between this and #457 the verify family is real: same report, same reason strings, same exit codes, two receipt formats.
Worth writing down somewhere eventually, though not in this PR: the basename mapping means the verifier and the importer share the landing layout without the manifest recording it. You noted it, and the next person to change _landing_relative_key needs to know a verifier depends on it. If a schema-4 receipt ever happens, carrying the relative key is the thing that removes the coupling.
Good work on both rounds, and on settling the contract with @Sagar-024 in writing before either of you wrote code. That is why these merged in two days instead of arguing in review.
Summary
VerificationReport/VerificationFinding/VerificationStatusinsrc/hflow/verification.pyfor thehflow verifyfamily ([Feature]: LeRobot prepared-manifest receipts are written but nothing verifies a delivered import #432; contract with Snapshot integrity receipts are written but nothing reads them: no way to verify a delivered snapshot #428).verify_lerobot_importand CLIhflow verify lerobot-importto check schema-3 prepared-manifest receipts (uri,content_id,size_bytes) without re-converting.0clean,1damaged,2unreadable,3unverifiable; unlistedlanding/extras ignored.import-lerobot-v3.mdnames the real verify path;FORMAT.mddocuments verify exit3.Test plan
uv run ruff check/ruff format --check/ty checkuv run pytest tests/test_verification.py -quv run pytest -q(1594 passed, 6 skipped)verification.pyfirst for Snapshot integrity receipts are written but nothing reads them: no way to verify a delivered snapshot #428 to import