Repository navigation
Conversation
…ctory apply wrote its backups to $SANDY_HOME/features/amap.rollout-backups. Sandy reads every directory under features/ as a feature, refuses one with subdirectories and no feature.json, and then mounts no feature at all, so every sandbox launched after an apply started without AMAP. Backups now go to AMAP_ROOT/rollout-backups. Every verb refuses while a directory of this tool's backups is still in the features directory, naming where to move it, and refuses a backup root that resolves inside it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…before naming a move features_clear() refused a left-over features/amap.rollout-backups before it checked where the backup root resolves. With AMAP_ROOT inside that directory, the refusal told the operator to move its contents into the root and then remove the directory, which deletes the moved backups and keeps them in the features directory. The root is now checked first, and the move is named only once the root is proven outside. The root resolves strictly: its existing part follows every link and a loop or an unreadable component is a refusal (RuntimeError included, as older Pythons raise for a loop). A missing tail is accepted, since backup and rollback create it, but a link to nothing or a '..' in it is refused. Containment compares spelling and the device and inode of each existing ancestor, so a spelling that differs only in case on a case-insensitive disk is still inside. Codex T2 blocker on d42870d6; Opus N1-N3. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y spelling The containment check read the features directory's identity and refused when it could not, so a host whose sandy features directory did not exist yet refused every verb with "cannot read". Such a directory has no identity to compare: a backup root is inside it when one of its ancestors is spelt as the features directory, with case ignored, which covers the spelling a case-insensitive disk would make the same directory once it is created. Tests: a missing features directory, accepted outside and refused by spelling and by case; a stat error other than ENOENT on the features directory or an ancestor is refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ry not created yet Comparing spellings with case ignored decides containment only for ASCII: a disk that also ignores Unicode normalization makes NFC and NFD spellings one directory, and Unicode case folding maps some non-ASCII letters (the Kelvin sign) to ASCII ones. When the features directory does not exist, a backup root or features directory spelt outside ASCII is now refused, with a remedy, instead of compared. An existing features directory is still compared by identity. Tests: NFC against NFD both ways, a non-ASCII root against an ASCII directory, and a Kelvin-sign directory against an ASCII root. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Supersedes #98: the same patch, rebased onto the current base, on a new branch (no force-push).
What
amap-codex-rollout.py applywrote its backups to$SANDY_HOME/features/amap.rollout-backups. Sandy reads every directory underfeatures/as a feature. It refuses one that has subdirectories and nofeature.json, and then mounts no feature at all:So every sandbox launched after an apply started without AMAP. Running sandboxes were unaffected.
AMAP_ROOT/rollout-backups, default~/amap/rollout-backups. The set-aside copy that rollback makes goes there too.check,apply,rollback) refuses whilefeatures/amap.rollout-backupsstill exists, and names where to move its contents. It also refuses a backup root that resolves inside the features directory.Host remedy (already given to the operator)
Then relaunch any sandbox launched since the apply.
Tests
test_apply_and_rollback_leave_nothing_beside_the_feature_in_sandys_features_directory: after apply and after rollback,features/lists onlyamap.test_a_backup_directory_left_in_sandys_features_directory_refuses_every_verb: all three verbs refuse with the move named, and nothing installs.test_a_backup_root_inside_sandys_features_directory_refuses.tests/test_codex_rollout.pypasses underunittest. The two features-directory tests fail against the base's code: they are the regression this fix removes.Not covered: a host run. I haven't checked sandy's own rule for which names under
features/it reads as a feature. This fix keeps everything of this tool's out of that directory, so the rule doesn't matter here.🤖 Generated with Claude Code