Repository navigation
Conversation
`pos eval run` and data collection now sync `--output_dir` through `sync_recording_dir`. It sets `delete_remote=False` and keeps `.unfinished` and `edits.jsonl` out of the upload. `positronic-inference stats` downloads the prefix and uploads nothing. pos3 0.5.0 adds `upload_exclude`. Until it is on PyPI, `pos3` comes from a git pin of `ddebabd`. Refs Positronic-Robotics/internal#264 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…fety/recording-sync-no-delete # Conflicts: # positronic/cli/eval/run.py
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.
Fixes Positronic-Robotics/internal#264.
Problem
pos eval runand both data collection entry points (main,main_sim) callpos3.sync(output_dir, sync_on_error=True). pos3 defaults todelete_remote=True. So each sync (every 300 s and at exit) deletes every key under the S3 prefix that the local cache does not hold. That includes episodes that another run uploaded to the same prefix after this run started.positronic-inference statsonly reads a prefix, but it callspos3.sync(output_dir). At exit it deletes every key that a live run uploaded after the stats download.Change
sync_recording_dirinpositronic/dataset/local_dataset.pyowns the arguments of a recording sync:sync_on_error=True,delete_remote=False,upload_exclude=[UNFINISHED_MARKER, EDITS_FILE].cli/eval/run.pyand bothdata_collection.pyentry points call it. The platform rollout console uses the sameupload_exclude.statscallspos3.download, so it writes nothing to the prefix.pos3>=0.5.0. pos3 0.5.0 addsupload_exclude(Refresh selected same-size files and configure upload exclusions pos3#16). The bump also brings in 0.4.0: an upload rate cap that is off by default, and a final sync that waits for a running background sync.Why the two files stay out of the upload:
.unfinished:DiskEpisodeWriterwrites it when an episode opens and removes it when the episode closes. A background sync during an episode uploads it. With no remote delete, the marker would stay in S3, and every reader would then skip the finished episode.edits.jsonl: other tools append to it in S3. The run's copy from the startup download is stale and differs in size, so pos3 would upload it over the newer remote copy.upload_excludedoes not filter the startup download. An old.unfinishedkey in S3 downloads into the cache, and the run hides that episode, as every other reader does.Draft until pos3 0.5.0 is on PyPI
pos3 main (
ddebabd) carries version 0.5.0, but the latest release on PyPI is 0.4.0. Until the release,[tool.uv.sources]pinspos3to git commitddebabd, with a TODO. When 0.5.0 is on PyPI, the pin goes anduv.lockresolvespos3from PyPI again. Thepos3>=0.5.0requirement stays as it is.The three
packagingchecks fail until then: they install the built wheel from PyPI, where onlypos3<=0.4.0exists.Known gaps
LocalDatasetWriterpicks the next episode id once, from its startup download, so two runs upload to the same keys. Telemetry sidecars undertelemetry/have a fixed name per process and are appended, so the later run's upload replaces the earlier run's spans the same way. A per-run subprefix or collision-free ids come later, as a separate design.abort()removes the local directory only, and the mirror no longer deletes remote keys. Readers skip such a directory, because it has nometa.json, and the next run on the prefix numbers its episodes after it. The files stay as storage residue.meta.jsonis now the only commit point in S3. Before, pos3 deleted the S3 marker only after all uploads in that sync succeeded. Now a reader can see a finished episode whose.mp4upload failed, until the next sync. A hard kill in that window makes it permanent.delete_local=Truestays. If a run's final upload fails, its episodes exist only in the local cache, and the next run on the same machine and prefix deletes them at its startup download. On a clean exit a failed final upload raises; on an error exit pos3 logsCleanup sync after error failedand the original exception fails the command. A hard kill skips the final sync.migrate_remote.pyandfake_dataset_generator.py. They are out of scope here.Tests
An in-memory S3 client (
InMemoryS3inpositronic/dataset/tests/utils.py) replacespos3._Mirror._get_client. One test calls the private_Mirror._sync_uploadsto run a background sync while an episode is open; the test says so.test_a_recording_sync_keeps_a_key_that_another_writer_put_after_it_startedtest_an_episode_that_a_sync_caught_open_lists_as_finished_in_s3test_a_recording_sync_does_not_revert_edits_that_grew_in_s3test_stats_writes_nothing_to_the_prefix_it_readsBefore and after, with the same tests:
main(sync_on_error=True;statsusespos3.sync)delete_remote=False, noupload_excludeLocal checks on
6920ec67:uv run --locked pytest4807 passed, 31 skipped;ruff check .andruff format --check .clean; pre-commit passed at commit.Revert risk: low. A revert brings back the remote delete. The change touches no stored data format.
🤖 Generated with Claude Code