diff --git a/lang/de.json b/lang/de.json index c0b12fc..16d4720 100644 --- a/lang/de.json +++ b/lang/de.json @@ -10,7 +10,7 @@ "Title": "Kosmos Storage Audit", "Intro1": "Prüft lokale Medienpfade aus Weltdokumenten, Paket-Packs und Manifesten gegen {dataRoot} und {publicRoot} und meldet nur broken-reference, non-package-to-package-reference und orphan-file.", "Intro2": "Nicht gemeldet werden reguläre Weltverweise auf Modul- oder Systemassets, wenn das Ziel im Owner-Paket selbst sichtbar referenziert ist; Wildcards gelten als gültig, sobald mindestens eine Datei passt.", - "Intro3": "orphan-file wird nur in weltlokalen oder explizit riskanten Bereichen gebildet, nie global für den gesamten {dataRoot}-Root; ChatMessages und andere flüchtige Quellen werden nicht geprüft." + "Intro3": "orphan-file wird für alle gefundenen Mediendateien gegen den aktuellen Referenzbestand geprüft; bekannte Sonderfälle wie abgeleitete Scene-Thumbnails sowie ChatMessages und andere flüchtige Quellen werden ausgeschlossen." }, "Action": { "Run": "Analyse starten", diff --git a/lang/en.json b/lang/en.json index 64fa3bb..f4da138 100644 --- a/lang/en.json +++ b/lang/en.json @@ -10,7 +10,7 @@ "Title": "Kosmos Storage Audit", "Intro1": "Checks local media paths from world documents, package packs, and manifests against {dataRoot} and {publicRoot}, and only reports broken-reference, non-package-to-package-reference, and orphan-file.", "Intro2": "Regular world references to module or system assets are not reported if the target is visibly referenced by its owning package; wildcards are treated as valid as soon as at least one file matches.", - "Intro3": "orphan-file is only produced for world-local or explicitly risky areas, never globally for the entire {dataRoot} root; ChatMessages and other transient sources are excluded." + "Intro3": "orphan-file is checked for every discovered media file against the current reference set; known special cases like derived scene thumbnails, ChatMessages, and other transient sources are excluded." }, "Action": { "Run": "Start Analysis", diff --git a/module.json b/module.json index 80488bc..364af6e 100644 --- a/module.json +++ b/module.json @@ -2,7 +2,7 @@ "id": "kosmos-storage-audit", "title": "Kosmos Storage Audit", "description": "Analyzes media references and risky storage locations across Foundry data and public roots.", - "version": "0.0.28", + "version": "0.0.29", "compatibility": { "minimum": "13", "verified": "13" diff --git a/scripts/core/finding-engine.js b/scripts/core/finding-engine.js index da30a6f..04c95e3 100644 --- a/scripts/core/finding-engine.js +++ b/scripts/core/finding-engine.js @@ -1,4 +1,4 @@ -import { classifyRisk, createCanonicalLocator, detectMediaKind, inferOwnerHint, isCorePublicPath, isStorageAreaPath } from "./path-utils.js"; +import { classifyRisk, createCanonicalLocator, detectMediaKind, inferOwnerHint } from "./path-utils.js"; function compareOwner(sourceScope, targetOwner) { if (!sourceScope) return "unknown"; @@ -128,7 +128,7 @@ export function buildFindings({ files, references, i18n, packageActivity }={}) { if (detectMediaKind(file.path) === "other") continue; const refs = matchingReferencesForFile(file, refsByLocator, wildcardReferences); if (refs.length) continue; - if (!shouldReportOrphan(file, resolvedReferences)) continue; + if (!shouldReportOrphan(file)) continue; const severity = (file.riskClass === "package-module") || (file.riskClass === "package-system") || (file.riskClass === "release-public") ? "warning" @@ -223,19 +223,9 @@ function wildcardToRegExp(pattern) { return new RegExp(`^${escaped}$`, "u"); } -function shouldReportOrphan(file, references) { +function shouldReportOrphan(file) { if (isDerivedSceneThumbnail(file)) return false; - if (file.riskClass === "stable-world") { - const worldId = file.ownerHint.ownerId; - return references.some(reference => reference.sourceScope?.ownerType === "world" && reference.sourceScope.ownerId === worldId); - } - if ((file.riskClass === "package-module") || (file.riskClass === "package-system")) { - return isStorageAreaPath(file); - } - if (file.riskClass === "release-public") { - return !isCorePublicPath(file); - } - return false; + return true; } function isInactiveModuleTarget(file, packageActivity) { diff --git a/tests/global-orphan-candidate-test.mjs b/tests/global-orphan-candidate-test.mjs new file mode 100644 index 0000000..f09c19e --- /dev/null +++ b/tests/global-orphan-candidate-test.mjs @@ -0,0 +1,38 @@ +import assert from "node:assert/strict"; +import { buildFindings, createFileRecord } from "../scripts/core/finding-engine.js"; +import { createFileLocator } from "../scripts/core/path-utils.js"; + +const files = [ + createFileRecord(createFileLocator("data", "assets/user-upload/example.webp"), 100), + createFileRecord(createFileLocator("data", "worlds/demo-world/assets/maps/map.webp"), 200), + createFileRecord(createFileLocator("public", "icons/custom/example.webp"), 300), + createFileRecord(createFileLocator("data", "worlds/demo-world/assets/scenes/exampleScene-thumb.webp"), 400) +]; + +const { findings } = buildFindings({ files, references: [] }); + +assert.equal( + findings.some(finding => finding.kind === "orphan-file" && finding.target.locator === "data:assets/user-upload/example.webp"), + true, + "unreferenced user assets should be reported as orphan candidates" +); + +assert.equal( + findings.some(finding => finding.kind === "orphan-file" && finding.target.locator === "data:worlds/demo-world/assets/maps/map.webp"), + true, + "unreferenced world assets should be reported as orphan candidates" +); + +assert.equal( + findings.some(finding => finding.kind === "orphan-file" && finding.target.locator === "public:icons/custom/example.webp"), + true, + "unreferenced public media should be reported as orphan candidates" +); + +assert.equal( + findings.some(finding => finding.kind === "orphan-file" && finding.target.locator === "data:worlds/demo-world/assets/scenes/exampleScene-thumb.webp"), + false, + "derived scene thumbnails must stay excluded from orphan candidates" +); + +console.log("global-orphan-candidate-test: ok");