cc3517fbbc
The skills-only special case (a `preserve_skills` kwarg plus nested closures keyed on the literal "skills") left cron/ and any future owned directory on the old rmtree-then-copytree path, which deletes user-added files on update and on --force reinstall. The rule is the same for all of them: a top-level owned directory is a container of roots; replace only the roots the payload ships, never the whole destination. Apply that rule to every owned directory, drop the kwarg and the string check, and lift the helpers to module level. `_remove_existing` keeps its symlink-no-follow semantics and `_real_dir` replaces any symlink or file on the destination path so the payload is never written outside the profile. The fresh-install path had nothing to preserve, so it needs no flag. Restore "skills" in DEFAULT_DIST_OWNED; removing it was never needed for the fix. Add one invariant test: a user-added cron/ file survives an update. Refs #110933