feat: address migration gaps (WIP) - #9487
Draft
pjwerneck wants to merge 15 commits into
Draft
Conversation
- Fix C2 item from migration gaps review
- Fix D1 item from migration gaps review
- Fix C1 item from migration gaps review - Pin dependents to the published version, not the bumped one, so a package released later in the same run does not need a version PyPI lacks
- Fix A2 item from migration gaps review, private folders only - Code quality fixes
- Fix A3 item from migration gaps review, floor mechanism only - Every floor starts at 0, so no peer is refused; protocol 1 has never shipped, so 0 is the only correct value today.
- Fix A3 item from migration gaps review, peer gate policy - A peer with UNKNOWN version is still skipped, because nothing can be negotiated without its version
- Fix A2b item from migration gaps review, completing A2 - A folder this client owns is reused after an upgrade, becasuse a peer that has not upgraded still looks for the old name - Delete _filter_patch_compatible, which has no caller left.
- B2: version the crypto key file; refuse an unknown later version because a private key cannot be rebuilt
- B4: version the persisted caches; reset on an unknown later version, because the client rebuilds them. On-disk format becomes {"version", "entries"}
- D2: freeze the VersionInfo V1 field set; every field V2 adds needs a default.
- A4: delete the two unused version exception classes.
- Fix B3 item from migration gaps review - Stamp the format version under a reserved _meta key, so older clients that treat every top-level key as a peer email skip it safely - Log and skip an unknown peer state instead of dropping the peer in silence; the writer keeps other entries, so the record is not erased on Drive
- Fix B1 item from migration gaps review; A2a already fixed the folder half - A later client can reshape a field while the object still parses, which gives a wrong restore silently. Ever load site already falls back to downloading all events, so refusing costs one slow cold start.
- Fix C3 case 1 from migration gaps review - The existing tests assert the negotiated version only; removing the protocol-0 codec fails this test and leaves those passing
- Fix A5 item from migration gaps review; the entry named the wrong pair, the different is between the two dataset methods, not jobs vs datasets.
- Fix A1 from migration gaps review. The dataset transport dropped the protocol version: the sender flattened every file and the receiver rebuilt a flat path, so a v1 dataset arrived with metadata that pointed at a directory that was not there. - create_dataset now writes one copy for each layout in the audience, and each copy gets its own collection. Every collection is shared with the whole audience, so a peer that upgrades later moves to the newer layout with no action by the owner. - The collection folder name carries the version as a v<n> infix before the separator. A client that predates multi-copy searches for the separator and so never lists a layout it cannot read. A protocol-0 name is unchanged, byte for byte. - Private data goes up with the copy that owns it. The copies hold separate private directories, so one upload of the newest left the others local only and a cold start did not restore them. - The watcher keeps the newest readable layout for each dataset, and warns and skips the rest. It keeps a local copy when the owner still publishes the dataset but in no layout this client reads, because that copy is the last one this client could read. - Login writes the remote version file. Only test helpers wrote it before, so the remote file kept the version that first created it. The mismatch check then prompted at every login, and a peer negotiated a job or dataset protocol version from a stale number. Closes the login item of A3. - The login mismatch prompt keeps local and remote data by default and repairs on the next sync. A full wipe is an explicit second choice. delete_unversioned_state is gone with the old first choice. A run with no terminal takes the keep-everything default instead of blocking.
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
Closes most of the migration gaps that block safe upgrades: private Drive folders are adopted by rename, P2P folders are found regardless of the version in the name, and durable surfaces (checkpoints, rolling state, crypto keys, peers JSON, local caches) carry or refuse versions instead of failing silently.
Adds a per-protocol minimum-supported floor (shipped inert at "0"), stops refusing peers on client semver mismatch, and hardens release/CI (export → publish → tag → bump, client migration tests in CI, numeric version ordering). Job protocol skew delivery is covered end-to-end; dataset transport multi-copy (A1) and a few process/policy items remain open.
Note
The base branch is
stephen/syft-client-migrations, notdev. This branch assumes that branch will be merged first.Changes
Done
create_datasetwrites one copy for each protocolversion in the audience. Each copy gets its own Drive collection, and every
collection reaches the whole audience. A peer that upgrades later therefore
moves to the newer layout with no action by the owner. The collection name
holds the version as a
v<n>infix before the separator. A client thatpredates this change therefore never lists a layout it cannot read. A
protocol-0 name does not change. The client uploads the private data of a
copy with that copy. A watcher keeps the newest readable layout for each
dataset, and warns and skips the rest.
_find_or_adopt_versioned_folderrenames the folderof the highest earlier version and keeps the data. The personal datasite
folder, the checkpoints folder, and the rolling-state folder all use it.
_find_p2p_folder_idfinds a folder whatever versionits name holds.
_filter_patch_compatibleis gone.MIN_SUPPORTED_*_PROTOCOL_VERSION. Thevalue travels as
min_supported_version, andnegotiate_protocol_versionenforces it for jobs and for datasets.
(
get_peer_compatibility_status).force_ignore_protocol_versionis gone.deletion is an explicit second choice. A run with no terminal takes the
keep-data answer, so a notebook or a scheduled run does not stop. Login
writes the version file on both sides. A second login therefore shows no
prompt, and a peer reads a current version.
ClientVersionMismatchErrorandProtocolVersionMismatchErrorare gone. The inert semverPROTOCOL_VERSIONfield stays on the wire.
logs a warning. See
test_unknown_peer_forced_path.py.client, and downloads all events instead. A local load that fails reports the
failure.
CRYPTO_KEYS_VERSION. A later version isrefused, because a private key cannot be rebuilt.
SYFT_peers.jsoncarries a version under_meta. The client logs anunknown peer state and skips it, and the rewrite of the raw map keeps the
entry.
PersistedDictwrites{"version", "entries"}. An old flat filereads as version 0, and a later version resets to empty.
--dependents publishedpins the published version, andprotocol_bump_missingcompares against the newest released protocol.just test-client-migrations, and again after a release.reads (
test_job_protocol_skew_delivery.py). A dataset reaches an audienceof mixed protocol versions (
test_dataset_multicopy_delivery.py)._version_ordercompares a version as a number, so"10"is after"2".VersionInfofields(
test_version_info_fields.py).live peer-schema dict.
Open items
One decision on A3 clears the first group. One release
cycle clears the second.
1. Waits on a decision (A3)
A peer can speak a protocol below the floor of a package. The client can refuse
it, warn about it, or go read-only. That question is open, and three items wait
on the answer. Every floor is
"0"today, so the mechanism refuses nothing andno user sees a difference.
target_protocol_versions_for_peerstakesmin(ours, theirs)and applies no floor. A1 makes this path live. Thecorrect action for a peer below the floor is part of the same decision.
because the correct result is not defined without the policy. A manual test
covers this ground now.
2. Closed by the next release
The first two items block the release. Do them before it. No code change on
this branch can close any of the three, because each one needs a release that
happened.
syft-migrationis not on PyPI, and no CD workflow releases it.syft-client, syft-job, and syft-dataset all depend on it with no pin. The
monorepo resolves the dependency from the workspace, so a local install
works. An install of the next release fails.
versions: syft-client 0.1.117, syft-job 0.1.39, syft-dataset 0.1.20. The
release job publishes the version that is on the branch, and PyPI refuses a
version that exists.
syft_client_install_sourceandattestation_token. The published wheel doesnot define these fields, because PyPI received it 12 days before the fields
arrived. A correct file needs the published wheel as the source.
3. Needs a rehearsal by a person
VersionInfohas a real migration pair. Both items close when one persondoes a full object version increase on a branch that never merges. That
person records each point where the tools say nothing. A synthetic V2 must not
merge: a released V2 freezes its schema and owes a migration forever.
4. Open by decision
5. Permanent, and not work
PROTOCOL_VERSIONfield (A4). It carries no meaning, and itmust stay on the wire, because a supported older client parses it.
6. A rare failure, kept loud on purpose
_expect_one, which raises andnames both folders. An automatic merge can put the data of a user out of
reach, so the client stops instead. Folder adoption makes this case rare.
7. Not measured
file_hashesreplays the event stream. The resetworks. The cost for a large datasite is not measured.
Testing
Asana task
https://app.asana.com/1/1185126988600652/project/1216249688888494/task/1217005273770094?focus=true