diff --git a/project/ticket-115/README.md b/project/ticket-115/README.md new file mode 100644 index 0000000..34a0a26 --- /dev/null +++ b/project/ticket-115/README.md @@ -0,0 +1,31 @@ +# Ticket 115: Keep default cleanup proposal tests independent of live Docker + +- **ID**: ticket-115 +- **Owner**: agent:codex +- **Status**: IN_PROGRESS +- **Workflow state**: PUBLICATION +- **Created**: 2026-10-31 + +## Goal and scope + +The full protected delivery preparation for ticket-114 stopped at a 30-second +unit-test timeout: a fake Docker proposal fixture escaped to live buildx du. +Inject the missing BuildKit measurement and prove the real inventory boundary +is never invoked. Preserve all existing proposal assertions and test deadlines. + +SESSION_EXECUTION_AUTHORIZATION: the user requested continuing repairs and +merges on 2026-10-31. This separate, disjoint test correction is a prerequisite +for ticket-114 and includes independent exact-head protected publication. + +## Acceptance criteria + +- [x] AC-01: Default-proposal tests cannot invoke the live BuildKit inventory. +- [ ] AC-02: Affected and complete tests plus managed governance pass. +- [ ] AC-03: Independent exact-head protected publication succeeds. + +## Validation + +The new boundary regression failed against the baseline with one live inventory +invocation. All 29 tests in the affected file now pass with their original +assertions and deadlines. Changed-file Ruff passed. The full suite, required +Python matrix and independent review remain publication work. diff --git a/project/ticket-115/intent.json b/project/ticket-115/intent.json new file mode 100644 index 0000000..c809d9f --- /dev/null +++ b/project/ticket-115/intent.json @@ -0,0 +1,73 @@ +{ + "schema": "new-project.intent/v3", + "ticket": "ticket-115", + "summary": "Keep default cleanup proposal tests independent of live Docker", + "workstream": "application", + "classification": { + "kind": "BUG", + "priority": "P1", + "origin": "requested" + }, + "allowedPaths": [ + "project/ticket-115/**", + "tests/unit/test_cleanup_safety.py" + ], + "forbiddenPaths": [ + "project/ticket-*/user-*.md" + ], + "stacks": [ + "python" + ], + "dependsOn": [], + "conflictsWith": [], + "integrationTicket": null, + "delivery": { + "acceptedBaseSha": "f8db03d927d9f86a577d6e2e882376208a6d127b", + "targetBranch": "main", + "outcome": "Independently publish deterministic default-proposal unit tests that cannot probe live Docker, unblocking protected verification of the pending disk-capacity correction.", + "nonGoals": [ + "No production cleanup or capacity behavior changes", + "No test exclusions, relaxed timeouts or protection changes" + ], + "complexity": "XS", + "estimatedMinutes": 5, + "budgets": { + "maxImplementationFiles": 1, + "maxAffectedComponents": 1, + "maxPublicInterfaceChanges": 0, + "maxRuntimeDependencies": 0 + }, + "architecture": { + "status": "accepted", + "decision": "Inject an empty BuildKit inventory into the existing fake Docker proposal fixture and assert that the live inventory function is never called.", + "components": [ + { + "name": "cleanup-proposal-tests", + "paths": [ + "tests/unit/test_cleanup_safety.py" + ] + } + ], + "responsibilityChanges": false, + "interfaceChanges": [], + "dataChanges": [], + "ui": { + "impact": "none", + "states": [], + "evidence": [] + }, + "rollback": "Revert through protected delivery." + }, + "runtimeDependencies": [], + "validation": [ + { + "criterion": "AC-01", + "commands": [ + "python -m pytest tests/unit/test_cleanup_safety.py -q", + "./project/governance-check.sh" + ], + "evidence": "project/ticket-115/README.md" + } + ] + } +} diff --git a/tests/unit/test_cleanup_safety.py b/tests/unit/test_cleanup_safety.py index f0e8592..ab28d13 100644 --- a/tests/unit/test_cleanup_safety.py +++ b/tests/unit/test_cleanup_safety.py @@ -253,6 +253,9 @@ def scan_service(self, service_type): @staticmethod def _cleaner(scanner, monkeypatch): cleaner = ServiceCleaner(scanner) + monkeypatch.setattr( + cleaner, "scan_docker_buildcache", lambda: {"error": None, "targets": []} + ) monkeypatch.setattr(cleaner, "list_ollama_models", list) monkeypatch.setattr(cleaner, "list_running_ollama_models", lambda: set()) monkeypatch.setattr( @@ -267,6 +270,20 @@ def _cleaner(scanner, monkeypatch): ) return cleaner + def test_fake_proposal_never_probes_live_buildkit(self, monkeypatch): + live_probes = [] + monkeypatch.setattr( + "fixos.cli._cleanup_space._docker_buildcache_scan", + lambda: live_probes.append(True) or {"error": None, "targets": []}, + ) + usage = {"Containers": {"size_gb": 3.0, "reclaimable_gb": 2.5}} + cleaner = self._cleaner(self._scanner(usage), monkeypatch) + + actions = cleaner.build_safe_age_actions() + + assert live_probes == [] + assert any(action["cleanup_kind"] == "docker-containers" for action in actions) + def test_default_plan_proposes_stopped_containers_and_images(self, monkeypatch): usage = { "Containers": {"size_gb": 3.0, "reclaimable_gb": 2.5},