Fix local card storage root resolution - #3301
Conversation
Keep local and spin cards under the resolved artifact datastore root when no explicit card root is configured, ensuring card writers and readers use the same location.
Greptile SummaryThis PR fixes local card storage root resolution. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (2): Last reviewed commit: "Handle empty local card datastore roots" | Re-trigger Greptile |
Treat empty local and spin datastore roots as missing so card root resolution preserves the legacy lookup behavior for older metadata. Co-authored-by: Cursor <cursoragent@cursor.com>
|
cc @valayDave |
Shriprasad-P
left a comment
There was a problem hiding this comment.
The fresh-run storage change looks correct, but I found a backward-compatibility regression for cards created before this change.
With a configured local datastore root, the previous behavior could store artifacts under <sysroot>/.metaflow while cards were written under the cwd-based .metaflow/mf.cards location.
I reproduced a run using the base revision with that layout. After switching to this PR, the reader uses the persisted ds-root and resolves the card location as <sysroot>/.metaflow/mf.cards. Both card list and the client API then fail to find the existing card in its legacy location.
Please keep the new resolved datastore location for new writes, but preserve a reader fallback to the legacy local/spin card root before reporting a card as missing.
There is also an empty-root edge case: CARD_LOCALROOT="" is currently treated as an explicit root because the check uses is not None. That leaves the card datastore with an empty root and can produce incorrect absolute paths or inconsistent read behavior. Please treat an empty value as unset, or reject it during configuration validation, and add coverage for it.
The fresh local/spin writer-reader symmetry, explicit non-empty card roots, and cloud backends otherwise look correct.
PR Type
Summary
Keep local and spin cards under the resolved artifact datastore root when no explicit card root is configured. Also ensure an explicit
METAFLOW_CARD_LOCALROOTis returned and used correctly.Issue
Fixes #2139
Reproduction
Runtime: Local datastore with a separate datastore sysroot, reproducing the storage configuration used with local Kubernetes.
Commands to run:
Where evidence shows up: The filesystem card location and the
card listoutput exercised by the integration test.Before (error / log snippet)
The card HTML was written under
<cwd>/.metaflow/mf.cardsinstead of the configured local datastore root.The explicit-root unit test also failed because
get_storage_root()returnedNonewhenCARD_LOCALROOTwas configured.After (evidence that fix works)
The card is written under
<sysroot>/.metaflow/mf.cards, no stray<cwd>/.metaflowdirectory is created, andcard listfinds the card.Root Cause
Artifact storage resolves
METAFLOW_DATASTORE_SYSROOT_LOCAL, but card storage independently searched upward from the current working directory. Consequently, artifacts and cards could use different roots.Additionally, when
CARD_LOCALROOTwas configured, the local/spin branch assigned it to a variable but did not return it, causing the method to returnNone.Why This Fix Is Correct
Local and spin card roots now follow a single resolution order:
CARD_LOCALROOT.mf.cardsto the already-resolved artifact datastore root.The card writer and reader both use this resolution logic, restoring the invariant that cards are read from the same location where they were written.
Failure Modes Considered
CARD_LOCALROOTcontinues to take precedence over the artifact datastore root.Tests
Local verification:
CI remains unchecked until the pull request checks complete.
Non-Goals
This change does not alter cloud card storage behavior, change card file layout, or remove the existing local fallback behavior.
AI Tool Usage
Cursor was used to assist with issue investigation, implementation, comments, and regression tests. I reviewed the changes and ran the relevant tests locally.