Namespace Serenity.Editor.ObsoleteAssetCleaner
Classes
SerenityObsoleteAssetCleaner
Removes leftovers from previous package versions after an upgrade. Unity's .unitypackage import
is additive — it never deletes files — so a customer upgrading over an older install keeps orphaned
scripts that no longer compile against the current codebase. The package owns
Assets/Serenity/Scripts, Tests and Documentation outright
(see Serenity.Editor.ObsoleteAssetCleaner.SerenityFrameworkOwnership): any file under those roots that is not listed in the
shipped ShippedAssetsSnapshot.json is an orphan and is moved to the OS trash (recoverable).
The cleaner lives in an isolated assembly with no references to any other Serenity assembly so it
keeps compiling — and keeps cleaning — even when a stale orphan breaks another assembly.
Orphans are not treated equally: Serenity.Editor.ObsoleteAssetCleaner.ObsoleteAssetClassifier.ClassifySweep(System.Collections.Generic.IReadOnlyList{System.String},System.Collections.Generic.IReadOnlyCollection{System.String},System.Func{System.String,System.Boolean},System.Func{System.String,System.Boolean},System.Func{System.String,Serenity.Editor.ObsoleteAssetCleaner.OrphanReconciliationEvidence}) decides what is safe to trash — or move, or
restore-and-trash — based on provenance rather than a raw count (see its remarks for the real-world
incidents that shaped it).
SerenityPackageImportScrubber
Post-import cleanup for Serenity package updates: the package is the sole owner of
Assets/Serenity/Scripts, Tests and Documentation, so once an import has laid its
files down, any file still under those roots that the import did not deliver is a leftover from a
previous version and goes to the OS trash (recoverable). Media/ is never touched (users modify
prefabs and themes in place).
The cleanup deliberately runs AFTER the import, never before. An earlier design trashed the owned roots
on importPackageStarted so the import could lay everything down fresh; that is self-defeating and
was removed. Unity does not release a trashed asset's GUID within the same import transaction, so every
incoming file carrying a just-trashed GUID was skipped: the working install was destroyed while only
assets with no prior GUID (genuinely new modules) were written back, leaving a fraction of the package
on disk and no framework that compiles. Importing additively — letting same-GUID files overwrite in
place and cleaning up afterwards — delivers the package intact.
Accepted destructive edge: partial Custom Package imports of the framework folders are UNSUPPORTED — a file the user deselects during a Serenity import is not part of the imported items, so the safety net treats the on-disk copy as a leftover and moves it to the trash (recoverable). This is a product decision, not an accident: those folders belong to the package, and deselecting framework files would otherwise leave exactly the stale-orphan states this mechanism exists to eliminate.
SerenityShippedSnapshotImportWatcher
Re-triggers the cleanup when a Serenity package update lands in an editor where the cleaner is already
resident: importing a new package brings a new ShippedAssetsSnapshot.json, and reacting to its
import lets the update self-apply (sweep + restore) without a manual editor restart. Also maintains the
package-import correlation record SerenityObsoleteAssetCleaner.ClassifySweep uses to tell
apart a stale-snapshot suspect (a file THIS import just wrote that the manifest omits) from an ordinary
previous-version leftover: every non-meta file this watcher sees imported under an owned root, for the
batch that brings the snapshot, is recorded alongside the snapshot's fingerprint. The record has a
two-phase lifecycle: PENDING while postprocess batches for the current import are still landing (any of
them can append — see Serenity.Editor.ObsoleteAssetCleaner.SerenityShippedSnapshotImportWatcher.AppendToImportRecordIfPending(System.String[])), then CONSUMED the moment a cleanup
pass actually reads it for classification (see Serenity.Editor.ObsoleteAssetCleaner.SerenityShippedSnapshotImportWatcher.TryLoadValidatedImportRecordPaths(System.String)), after
which it is frozen until the next snapshot import overwrites it wholesale — so an unrelated asset import
that happens to land under an owned root AFTER the cleanup pass already ran can never silently grow a
record that was already classified against.
Enums
OrphanReconciliationAction
The reconciliation action SerenityObsoleteAssetCleaner.ClassifyReconciliationAction plans for one product orphan.
Public (not internal) solely so NUnit's public ExpectedResult test signatures can return it.