Skip to content

Port the file-tier command family from NDI-matlab - #315

Merged
stevevanhooser merged 2 commits into
mainfrom
claude/file-tier-parity
Sep 16, 2026
Merged

stevevanhooser merged 2 commits into
mainfrom
claude/file-tier-parity

Conversation

@stevevanhooser

Copy link
Copy Markdown
Contributor

Summary

Brings the file-tier client surface to Python at parity with NDI-matlab#990. Four new wrappers in ndi.cloud.api.files, backed by mock unit tests that mirror FileTierMockTest.m:

Wrapper Endpoint Purpose
setFileTier(dataset_id, document_ids, target_tier, id_namespace="auto") POST /datasets/{d}/file-tier-jobs kicks off an async job that moves the files backing a set of documents to a target S3 storage class
getFileTierJob(job_id) GET /file-tier-jobs/{jobId} one poll
waitForFileTierJob(job_id, timeout=600, initial_interval=3, max_interval=30, backoff_factor=2) poll loop over getFileTierJob wait until terminal (completed | failed | superseded) or client-side timeout
getFileTier(dataset_id, document_id) composes over getDocument returns {counts, dominant, notes, updatedAt, raw} from the doc's cached filesTier

Selector semantics match MATLAB: document_ids may mix cloud _id and NDI id shapes; the server infers per-selector when id_namespace="auto" (default), and "cloud" / "ndi" force a kind field on every selector. target_tier stays a plain str at the wire level so PSEUDO_COLD remains reachable for non-production tests — the docstring names the five production tiers explicitly, and the exported FileTier Literal gives callers strict typing when they want it.

waitForFileTierJob follows the existing waitForBulkUpload contract: returns the last status dict (with state='timeout' and elapsed on timeout), so the caller reads state themselves. A transient poll error is not treated as terminal — a gateway blip would otherwise be mistaken for a dead job. The MATLAB FileTierMockTest pins port over as unit tests exercising each terminal state, the timeout path, and gateway-blip retry.

Bridge YAML gets four new entries under files.py with matlab_last_sync_hash: 6fdec7e7 (the merge commit of NDI-matlab#990).

Design reference: ndi-cloud-node/manuals/file-tier-design.md (server PRs #139 + #140).

Test plan

  • pytest tests/test_cloud_file_tier.py — 18 tests, all pass
  • pytest tests/test_matlab_bridge_completeness.py tests/test_matlab_bridge_status.py tests/test_matlab_bridge_hashes.py tests/test_every_module_imports.py — all pass, no regressions
  • pytest tests/test_cloud_api_datasets.py tests/test_cloud_api_documents.py — adjacent cloud API tests still pass
  • ruff check and black --check clean on the touched files
  • Live cloud test — deferred; NDI-python's live-cloud suite is in test_cloud_live.py with module-scoped fixtures that don't currently cover file-tier. Add-on can follow once the live cloud stage is green server-side.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AyvQiNcA83wxQN82vM1QD6


Generated by Claude Code

Mirrors NDI-matlab#990 (matlab HEAD 6fdec7e7). Adds four wrappers to
ndi.cloud.api.files plus mock tests for the poll loop:

  setFileTier          POST /datasets/{d}/file-tier-jobs
  getFileTierJob       GET  /file-tier-jobs/{jobId}
  waitForFileTierJob   poll loop over getFileTierJob
  getFileTier          projects filesTier off a documents.getDocument

Selector semantics match the MATLAB side: document_ids may mix cloud
_id and NDI id shapes, id_namespace defaults to "auto" so the server
infers per-selector, and "cloud"/"ndi" force a kind field on every
selector. target_tier stays a plain str at the wire level so
PSEUDO_COLD stays reachable for non-production tests; the docstring
names the five production tiers and the exported FileTier Literal
gives callers strict typing when they want it.

waitForFileTierJob follows the existing waitForBulkUpload contract:
returns the last status dict, with state='timeout' + elapsed on
timeout, so the caller reads state ('completed' | 'failed' |
'superseded') themselves. A transient poll error is NOT treated as
terminal -- the FileTierMockTest pin ports over as tests exercising
each terminal state, the timeout path, and gateway-blip retry.

Bridge YAML gets four new entries under files.py with matlab_last_sync_hash
6fdec7e7 (the merge commit of NDI-matlab#990).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AyvQiNcA83wxQN82vM1QD6
NDI-matlab#990 (the file-tier PR being ported in this branch) also
added two rows to url.m for the file-tier endpoints
(create_file_tier_job, get_file_tier_job). Python inlines every
route at its call site (CloudClient._build_url), so those two rows
have nothing to add on the Python side -- setFileTier and
getFileTierJob in api/files.py name them directly. Bump the
recorded hash so the drift check stops firing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AyvQiNcA83wxQN82vM1QD6
@stevevanhooser
stevevanhooser merged commit 3fba97e into main Sep 16, 2026
9 checks passed
@stevevanhooser
stevevanhooser deleted the claude/file-tier-parity branch September 16, 2026 13:21
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.

2 participants