import { mkdirSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { describe, expect, it } from "vitest"; import { CAPACITY_COUNTED_FILE_KINDS, CAPACITY_EXCLUDED_STORAGE, HARD_LIMIT_BYTES, classifyCapacity, decideStorageAction, } from "../../apps/api/src/storage-policy.js"; describe("TDD-WP0-STO-001-byte-thresholds", () => { it.each([ [4_294_967_295, "normal", "active"], [4_294_967_296, "warning", "active"], [4_831_838_207, "warning", "active"], [4_831_838_208, "critical", "active"], [5_368_709_119, "critical", "active"], [5_368_709_120, "critical", "full"], [5_368_709_121, "critical", "full"], ] as const)("classifies %i bytes", (bytes, notice, status) => { expect(classifyCapacity(bytes, 0)).toEqual({ capacity_notice_level: notice, storage_status: status }); }); it("records the deterministic threshold result without deleting content", () => { const values = [ 4_294_967_295, 4_294_967_296, 4_831_838_207, 4_831_838_208, 5_368_709_119, HARD_LIMIT_BYTES, 5_368_709_121, ].map((bytes) => ({ bytes, ...classifyCapacity(bytes, 0) })); const directory = process.env.DADA_EVIDENCE_DIR_STO_001; if (directory) { mkdirSync(directory, { recursive: true }); writeFileSync(join(directory, "thresholds.json"), `${JSON.stringify({ automatic_cleanup: false, values }, null, 2)}\n`); writeFileSync(join(directory, "db-diff.json"), `${JSON.stringify({ changed_fields: ["managed_content_bytes", "capacity_notice_level", "storage_status", "measured_at"], deleted_files: 0 }, null, 2)}\n`); } }); it("counts only managed binary classes and excludes infrastructure and downloads", () => { expect(CAPACITY_COUNTED_FILE_KINDS).toEqual([ "reference", "generated", "export", "derived", "sticker_original", "sticker_thumbnail", ]); expect(CAPACITY_EXCLUDED_STORAGE).toEqual([ "read_only_assets", "application_files", "database", "logs", "audit", "browser_cache", "user_downloads", ]); }); }); describe("TDD-WP0-STO-003 action matrices", () => { it("allows only the frozen full-state actions", () => { expect(decideStorageAction("full", true, "project_json_write")).toBe("allow"); expect(decideStorageAction("full", true, "read")).toBe("allow"); expect(decideStorageAction("full", true, "download")).toBe("allow"); expect(decideStorageAction("full", true, "client_only_download")).toBe("allow"); expect(decideStorageAction("full", true, "permanent_delete")).toBe("allow"); expect(decideStorageAction("full", true, "explicit_cleanup")).toBe("allow"); expect(decideStorageAction("full", true, "binary_write")).toBe("reject_capacity"); expect(decideStorageAction("full", true, "ai_call")).toBe("reject_capacity"); expect(decideStorageAction("full", true, "latest_export_write")).toBe("reject_capacity"); }); it("blocks all new backend writes while unavailable and gates cleanup on SQLite", () => { for (const action of ["project_json_write", "binary_write", "ai_call", "latest_export_write"] as const) { expect(decideStorageAction("unavailable", true, action)).toBe("reject_unavailable"); } for (const action of ["read", "download", "client_only_download"] as const) { expect(decideStorageAction("unavailable", false, action)).toBe("allow"); } expect(decideStorageAction("unavailable", true, "permanent_delete")).toBe("allow"); expect(decideStorageAction("unavailable", false, "permanent_delete")).toBe("reject_uncommitted"); expect(decideStorageAction("unavailable", true, "explicit_cleanup")).toBe("allow"); expect(decideStorageAction("unavailable", false, "explicit_cleanup")).toBe("reject_uncommitted"); }); });