feat(encord) 3/5: Pull from Encord - #384
Open
jonlwowski012 wants to merge 3 commits into
Open
Conversation
Lays the groundwork for the Encord curation-SaaS workbench tool without exposing a verb yet. This is the first of five stacked PRs that replace nebius#339 (prereqs -> push -> pull -> curate -> verify). Shared fixes surfaced while running Encord live: - StorageClient bounds every boto network wait (connect 10s, read 60s, 16 pooled connections); a stalled TCP connection during workflow-preflight staging blocked a submit indefinitely. - parse_bucket_uri becomes public so a new tool reuses it instead of re-implementing S3 URI parsing; the two private importers migrated. - json_stdout_contract reads the value of enum-typed output_format options, which a (str, Enum) member otherwise stringifies as OutputFormat.json. - scripts/build_docs.sh guards an empty-array expansion that bash 3.2 rejects under set -u. Encord foundations (npa.workbench.encord, no CLI yet): - schemas: PushReceipt, CurateReceipt, PullManifest, RoundtripReport, error types, schema ids and filenames. - identity: exact identity via npa.source_uri client metadata and normalized object URLs; same-basename and percent-encoding aliasing are pinned, and conflicting signals fail closed. - integrity: single-part ETag as md5, streamed sha256 otherwise. - storage: the S3-only artifact writer. - client: the one seam that touches the Encord SDK (lazy import) with title-or-id resolution for integrations, folders, datasets, projects and collections. - credentials: exactly two transports, ENCORD_SSH_KEY_B64 (pods) and ENCORD_SSH_KEY_FILE (laptops); a raw PEM paste is rejected. - npa[encord] optional extra pins the SDK. Preflight: `npa workbench health preflight --checks encord` proves the credential before anyone spends SaaS time (missing -> WARN naming the two transports, SDK absent -> WARN with a pip remedy, handshake failure -> FAIL). Tests: the Encord unit tests are split per module with shared fakes in npa/tests/workbench/encord_fakes.py; the enum stdout-contract fix gets its own unit test. docs/cli/health.md is regenerated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Second of five stacked PRs replacing nebius#339 (prereqs -> push -> pull -> curate -> verify). First user-facing verb. `npa workbench encord push` registers S3 media in place into an Encord storage folder (default `register` mode: bytes stay in the bucket through an S3-compatible integration; `upload` copies bytes to Encord) and links the folder to a dataset. - Write-ahead `planned` receipt before the first Encord mutation, so an uncatchable kill still leaves a durable record of intent. - Caller-side idempotency in both modes: identities resolve against the folder before anything is sent, so a retried stage makes zero registration round-trips and copies no duplicate bytes; register never falls through to upload. - Exact identity via npa.source_uri client metadata; same-basename objects resolve to distinct items and conflicting signals fail the item closed. - Per-item size, ETag, and content checksum in the receipt; counters derived from per-item outcomes. An empty --integration in register mode is rejected before any I/O; .mcap inputs fail closed as experimental_error rows. `encord cleanup --title-prefix` tears down run-scoped folders, collections and presets and reports datasets (the SDK cannot delete them). Surface: the `npa workbench encord` Typer group and `npa.sdk.workbench.encord` module (one implementation, thin clients; every verb under @json_stdout_contract, EncordToolError and path-contract violations exit 1, bugs propagate as exit 2); `encord` joins the three-tier seam set. toolRef `workbench.encord.push` with `encord-push.yaml` (CPU-only, plan-only twin in the live submit matrix); renderer secret hint, `npa[encord]` pip extra for image-less stages, and a fail-closed setup preamble when ENCORD_SSH_KEY_B64 is empty. Operator doc for push and cleanup, catalog-doc row, generated CLI docs. Tests: test_encord_push.py, test_encord_cleanup.py (shared fakes gain folder_item, FakeUploadFolder, FakeDownloadStorage), test_encord_cli.py, test_encord_workflow.py, push row in the spec-declared-outputs guardrail. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Third of five stacked PRs replacing nebius#339 (prereqs -> push -> pull -> curate -> verify). Closes the loop through the human path: register in place, curate in the Encord app, pull the Collection back to S3. `npa workbench encord pull --source {collection|dataset|project} --source-id ... --output-path s3://...` materializes media, per-item JSON and (for projects) label rows into an S3 prefix with an npa.encord.pull_manifest.v1 manifest. - Zero-egress by default: when the signed URL points at the configured endpoint the item is copied server-side and the destination ETag recorded; a failed copy falls back to download and records copy_error so paid egress is never silent. - Downloads are hashed in-stream (sha256); registered copies carry the source md5-as-ETag, so verify has something to compare later. - One item's failed fetch becomes an error row, never a lost record; the manifest is written before any failure exit and any failed item fails the command closed. Composite items are per-item errors. Transfers run in a bounded thread pool. Surface: CLI `pull`, SDK `pull`, toolRef `workbench.encord.pull` with `encord-pull.yaml` (CPU-only, plan-only twin in the live matrix), operator doc sections for in-app curation and pull, catalog-doc row, regenerated CLI docs. Tests: test_encord_pull.py (shared fakes gain stub_httpx_stream), pull cases in test_encord_cli.py and test_encord_workflow.py, pull row in the spec-declared-outputs guardrail. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Third of five stacked PRs replacing #339 (prereqs → push → pull → headless curate → verify). Stacked on
encord/02-push; review only the last commit until that merges.flowchart LR S3[("Your S3 bucket")] FOUND["Foundations · PR 1<br/>contracts · exact identity · checksums<br/>Encord SDK seam · credentials + preflight"] PUSH["encord push (+ cleanup) · PR 2"] ENC["Encord folder / dataset"] CUR["encord curate (headless) · PR 4"] HCUR{{"or: Encord app"}} COLL["Curated Collection"] PULL["encord pull · this PR"] OUT[("Curated media + labels<br/>+ manifest, in S3")] VER["encord verify · PR 5"] FOUND -.-> PUSH & CUR & PULL & VER S3 --> PUSH --> ENC ENC --> CUR --> COLL ENC -.-> HCUR -.-> COLL COLL --> PULL --> OUT ENC --> PULL OUT --> VER PUSH -. receipt .-> VER classDef done fill:#d9ead3,stroke:#38761d,color:#000 classDef this fill:#fff2cc,stroke:#bf9000,stroke-width:3px,color:#000 classDef todo fill:#f3f3f3,stroke:#999,stroke-dasharray:4 3,color:#777 class FOUND,PUSH done class PULL this class CUR,VER todoThis PR solves the Encord → S3 edge, from either a dataset or a curated Collection. With push and pull both merged the loop closes for the first time through the human path: register in place, curate in the Encord app, pull the Collection back to S3 with a lineage manifest.
encord pullnpa workbench encord pull --source {collection|dataset|project} --source-id <id-or-title> --output-path s3://…materializes media, per-item JSON, and (for projects) label rows into an S3 prefix with annpa.encord.pull_manifest.v1manifest.copy_error, so paid egress is never silent.verifyverb has something to compare.Surface
pulland SDKpullon the group and module PR 2 created;PullManifestre-exported.workbench.encord.pullwithencord-pull.yaml(CPU-only, terminal at the manifest; plan-only twin in the live matrix, because no standalone submit can supply a human-curated id).docs/cli/encord.md.Tests
test_encord_pull.py(same-endpoint detection for path-style and virtual-hosted URLs, server-side copy, composite-item error, cross-origin download through a stubbedhttpx.stream, copy-fallback reason, per-source enumeration, manifest on errors, one raising signed-URL fetch keeps every record, labels crash still writes the manifest, expired-URL retry, empty source fails closed). The shared fakes gainstub_httpx_stream. CLI tests: pull help, text and JSON output, path contract, bad--source, missing-credential path,EncordToolErrorexit. Workflow tests: pull spec structure, argv rendering, CPU-only resources, secret hint.Validation
validate-spec encord-pull.yamlmake testorigin/main, no new failuresStack
encord push(+ cleanup)encord pullencord curate(+system-info),encord-roundtrip-smoke.yamlencord verify, skill + docs completion🤖 Generated with Claude Code