Live sync removes files outside packaging/files.json (dry run first) #27

Merged
claude merged 4 commits from oss-oo/z-live-sync-prune into main 2026-10-28 02:39:51 +00:00
Member

Owner request (Claudiu, 2026-10-28): remove icons/chat-bubble.svg from the live folder and teach the live sync to delete files that packaging/files.json does not name.

The copy install never deletes (its contract for every user: only two known, byte-identical retired icons go), so leftovers stay. On the station: icons/chat-bubble.svg (the upstream ChatGPT artwork z dropped in 1.0.0, still byte-identical to upstream ef77e98) and a stale __pycache__.

  • .zcode/skills/cinnamon-z-usage-live-sync/scripts/prune_unmanaged.py: dry run by default (lists every entry the manifest does not name, __pycache__ included), --apply removes exactly that list. Only inside a real applets/<uuid> folder; never follows a symlink (a symlink is removed as a link); refuses a symlinked or foreign folder and a symlinked managed path.
  • audit_deployment.py: reports EXTRA (fails the audit) and CACHE (__pycache__, tolerated since the settings dialog rewrites it) entries; right after a sync: EXPECTED=24 VALID=24 SYMLINKS=0 MISMATCHES=0 EXTRA=0 CACHE=0.
  • Skill: dry-run list first, then the warning line, sleep 1, install, prune, targeted ReloadXlet, audit. Release skill: the new summary line.
  • tests/test_live_sync_tools.py: dry run, apply, symlinks in and out, refusals, audit counts.

No payload change: install.sh and scripts/package.py are untouched, install.zip stays byte-identical, so no release is needed.

Live dry run (read-only, before this PR): WOULD REMOVE 3 __pycache__/*.pyc, icons/chat-bubble.svg, __pycache__/.

🤖 Generated with Claude Code

Owner request (Claudiu, 2026-10-28): remove `icons/chat-bubble.svg` from the live folder and teach the live sync to delete files that `packaging/files.json` does not name. The copy install never deletes (its contract for every user: only two known, byte-identical retired icons go), so leftovers stay. On the station: `icons/chat-bubble.svg` (the upstream ChatGPT artwork z dropped in 1.0.0, still byte-identical to upstream ef77e98) and a stale `__pycache__`. - `.zcode/skills/cinnamon-z-usage-live-sync/scripts/prune_unmanaged.py`: dry run by default (lists every entry the manifest does not name, `__pycache__` included), `--apply` removes exactly that list. Only inside a real `applets/<uuid>` folder; never follows a symlink (a symlink is removed as a link); refuses a symlinked or foreign folder and a symlinked managed path. - `audit_deployment.py`: reports `EXTRA` (fails the audit) and `CACHE` (`__pycache__`, tolerated since the settings dialog rewrites it) entries; right after a sync: `EXPECTED=24 VALID=24 SYMLINKS=0 MISMATCHES=0 EXTRA=0 CACHE=0`. - Skill: dry-run list first, then the warning line, `sleep 1`, install, prune, targeted ReloadXlet, audit. Release skill: the new summary line. - `tests/test_live_sync_tools.py`: dry run, apply, symlinks in and out, refusals, audit counts. No payload change: `install.sh` and `scripts/package.py` are untouched, `install.zip` stays byte-identical, so no release is needed. Live dry run (read-only, before this PR): `WOULD REMOVE` 3 `__pycache__/*.pyc`, `icons/chat-bubble.svg`, `__pycache__/`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
claude agent added 1 commit 2026-10-28 02:03:57 +00:00
Live sync removes files outside packaging/files.json (dry run first)
All checks were successful
Checks / Functional checks (pull_request) Successful in 57s
8d3544f8e2
Owner request (2026-10-28): the copy install never deletes, so leftovers
of older installs stay in the live applet folder (icons/chat-bubble.svg,
the upstream ChatGPT artwork z dropped in 1.0.0, still byte-identical to
upstream ef77e98; stale __pycache__). The live-sync skill now prunes them:

- scripts/prune_unmanaged.py lists every entry the manifest does not
  name (dry run by default) and removes exactly that list with --apply;
  it works only inside a real applets/<uuid> folder, never follows a
  symlink (a symlink is removed as a link) and refuses a symlinked or
  foreign folder or a symlinked managed path.
- audit_deployment.py reports EXTRA (fails the audit) and CACHE
  (__pycache__, tolerated) entries; right after a sync the summary reads
  EXTRA=0 CACHE=0.
- The skill: dry-run list first, then the warning line, install, prune,
  targeted ReloadXlet. install.sh keeps its contract for every user
  (only two known retired icons are ever deleted), so the payload and
  install.zip are unchanged.
- tests/test_live_sync_tools.py covers the dry run, the apply, symlinks
  in and out of the folder, the refusals and the audit counts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 1 (#27): the prune removes only its dry run, safely
All checks were successful
Checks / Functional checks (pull_request) Successful in 53s
135d11ed2c
- Manifest paths must be canonical ("./a", "a//b", "a/", "." rejected):
  otherwise the prune deleted the file the installer had just written.
- The audit fails a symlinked, below-a-symlink or missing folder and
  never prints EXTRA=0 without a completed scan (EXTRA=? CACHE=?);
  unreadable directories fail loudly; empty leftover directories count
  as EXTRA; CACHE is only __pycache__ and the .pyc files directly in it.
- prune_unmanaged.py requires --project, --installed and --plan (no
  stale defaults, no --manifest). The dry run writes the plan; --apply
  removes only planned entries that are still unmanaged and keeps and
  reports anything new (exit 1). It refuses a git checkout or a folder
  overlapping the project, removes through directory handles with
  O_NOFOLLOW (a swap between scan and unlink cannot lead outside), has
  nothing to prune on a first install and handles names that are not
  UTF-8.
- Skill: the dry run on its own first, install stops on failure, the
  reload follows a failed prune; the station helper is two-step (dry
  run, then --apply after the warning line).
- Tests: every finding above, whole-tree checks around the dry run and
  the symlink-safe removal itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 2 (#27): one-shot plans bound to each entry
All checks were successful
Checks / Functional checks (pull_request) Successful in 40s
7f5003e79d
- A plan serves one --apply (removed as soon as it is read), expires
  after 15 minutes, and binds every entry to its inode, size and mtime:
  a file re-created or changed after the dry run is kept and reported.
- The dry run refuses a plan path inside the applet folder or the
  project and never replaces a file that is not a dry-run plan.
- --apply opens the folder once and checks it is the scanned one.
- Listings escape control characters (no faked lines); the audit counts
  only real symlink cases under SYMLINKS.
- Skill: absolute plan path, precise wording, the helper's --apply.
- Tests: one-shot and expiry, changed entries, plan paths, the real
  manifest is canonical, a scan error that also fails under root.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 3 (#27): unambiguous listings, plan use-up via symlinks
All checks were successful
Checks / Functional checks (pull_request) Successful in 41s
2d0b6090a9
- Listings: bytes that are not UTF-8 read \xNN, other unprintable
  characters \uNNNN, a literal backslash \\ (no ambiguous escapes).
- A plan named through a symlink is used up at its real path too.
- README: directories are bound to their inode only (an emptied,
  re-created directory may go too; rmdir only removes empty ones).
- Tests: a future-dated plan, a folder swapped after the scan, the
  audit command's failed scan in-process (also under root), the
  symlinked plan, the new escapes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent merged commit 8645c8b13f into main 2026-10-28 02:39:51 +00:00
claude agent deleted branch oss-oo/z-live-sync-prune 2026-10-28 02:39:51 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
OSS-Singularity/cinnamon-z-usage!27
No description provided.