Uninstall summary names what it kept
TASK-IMP-106: Uninstall summary names what it kept
Summary
uninstall.sh deliberately keeps the operator's corpus, status page, CHANGELOG, and BRAIN - the right default - and never says so. Someone who uninstalls expects the repo to be clean and finds task folders and memory still there, with no way to know it was intentional. Add a summary that names what was removed, what was kept and why, and how to remove the kept material by hand.
Problem
uninstall.sh references docs/tasks twice and leaves it alone by design: the corpus is the operator's work, not the machine's. But the summary says nothing about it. This is the same failure shape as TASK-IMP-095 (gates.env clobbered silently) and TASK-IMP-096 (non-git install silently useless) - a correct default, undocumented at the exact moment it surprises someone - and both of those proved worth fixing.
Silence at that moment has a specific cost: the operator either assumes the uninstall failed and re-runs it, or deletes the corpus by hand to "finish the job" and loses the work the default existed to protect.
Proposed Solution
Print a two-part summary on successful uninstall. Removed: the vendored machine and the agent surface, each named. Kept: docs/tasks/ (your corpus), docs/status/, CHANGELOG.md, .cyberos/memory (BRAIN) - with a one-line reason and the verbatim command to remove them for an operator who means it. Names come from what the run actually did, not a hard-coded list, so the summary cannot drift from the behavior.
Alternatives Considered
- Prompt to delete the corpus. Rejected: uninstall is frequently non-interactive, and a prompt that defaults to deleting an operator's work is a footgun with a confirmation step.
- A
--purgeflag that removes everything. Rejected here as scope creep - the defect is silence, not a missing capability. Worth its own task if anyone asks. - Documentation only (GUIDE note). Rejected: the surprise happens at the terminal, and that is where the answer has to be.
Success Metrics
- Primary: a successful uninstall names every kept path with a reason and the removal command - suite-asserted against the real run's output. Baseline: zero mentions today.
- Guardrail: the summary reflects what the run did (derived, not hard-coded) - a kept path absent from the repo is not claimed as kept.
Scope
In scope: the uninstall summary block, suite arms.
Out of scope / Non-Goals
- Changing what uninstall removes or keeps - the state machine is correct and this task must not touch it.
- A purge flag.
- The install-side summary (TASK-IMP-096 already covers its case).
Dependencies
depends_on TASK-IMP-103: both edit uninstall.sh, and 103 adds the lock-removal branch whose outcome this summary must report. Serialised, not parallel. Per TASK-IMP-101's evidence gate, 103's coverage-gate artefact is the evidence.
AI Authorship Disclosure
- Tools used: Claude (Fable 5) running the CyberOS task-author skill inside Cowork.
- Scope: spec drafted from IMPROVEMENT_HANDOFF.md IMP-27, verified against uninstall.sh on merged main; implementation under ship-tasks supervision.
- Human review: scope approved at the 2026-07-17 PLAN gate; both HITL gates are recorded human verdicts.
1. Description (normative)
- 1.1 On successful uninstall, the summary MUST name what was removed (the vendored machine and the agent surface entries the run actually removed).
- 1.2 The summary MUST name each kept path with a one-line reason:
docs/tasks/(the corpus),docs/status/,CHANGELOG.md,.cyberos/memory(BRAIN). - 1.3 The summary MUST print the verbatim command an operator can run to remove the kept material themselves.
- 1.4 Kept paths MUST be derived from what exists after the run - a path that is not present MUST NOT be claimed as kept.
- 1.5 The summary MUST NOT change what uninstall removes or keeps.
2. Acceptance criteria
- [ ] AC 1 (traces_to: #1.1, #1.2, #1.3) - uninstall on a populated repo prints removed entries, all four kept paths with reasons, and the manual-removal command - test:
tools/install/tests/test_install_hygiene.sh::t20_uninstall_summary_names_kept - [ ] AC 2 (traces_to: #1.4) - uninstall on a repo with no
docs/status/does not claim it as kept - test:tools/install/tests/test_install_hygiene.sh::t21_uninstall_summary_derived_not_hardcoded - [ ] AC 3 (traces_to: #1.5) - the set of files present after uninstall is byte-identical to today's behavior - test:
tools/install/tests/test_install_hygiene.sh::t22_uninstall_behavior_unchanged
3. Edge cases
- Uninstall on a repo that was never installed: no removal summary - it MUST NOT print a kept list for a machine that was not there (nothing was kept; nothing was removed).
- BRAIN present but empty: still named as kept - the directory is the operator's, and its emptiness is not the uninstaller's judgment to make.
- Corpus present but
docs/status/absent (never rendered): per 1.4, status is omitted from the kept list rather than claimed. - A partially-removed machine from an interrupted earlier uninstall: the summary reports what this run removed, not what it wished it had removed.
- Security-class: prints paths that already exist in the repo; interpolates no user-supplied string into a command. The printed removal command is documentation, never executed by the script.
Audit
§1 - Verdict summary
Spec is 72 lines, 5 §1 clauses, 3 ACs, 5 edge cases. Same failure shape as TASK-IMP-095/096 - a correct default undocumented at the moment it surprises someone - and both proved worth fixing. Passes after 6 findings.
§2 - Findings (all resolved)
ISS-001 - depends_on was empty despite sharing uninstall.sh with 103
103 adds the lock-removal branch this summary reports; concurrent edits to one file violate §11a. Resolved: depends_on: [TASK-IMP-103] with reciprocal blocks, evidence gate named.
ISS-002 - A hard-coded kept list would drift from behavior
Printing four fixed paths claims a path that may not exist. Resolved: §1 #1.4 requires derivation; AC 2 asserts a missing status dir is not claimed.
ISS-003 - Scope creep toward a purge flag
The defect is silence, not a missing capability. Resolved: explicit Non-Goal, keeping the task at one hour.
ISS-004 - Summary could imply uninstall changed behavior
A new kept list might read as a new policy. Resolved: §1 #1.5 forbids behavior change; AC 3 asserts the post-uninstall file set is byte-identical.
ISS-005 - Never-installed repo would print a misleading kept list
Nothing was kept because nothing was removed. Resolved: §3 edge case suppresses the block entirely.
ISS-006 - Printed removal command is a shell string
A command in output the script might later execute is an injection surface. Resolved: §3 security-class fixes it as documentation, never executed, no interpolation.
§3 - Resolution
All 6 concerns addressed. The machine floor (task-lint) ran FIRST and was clean before any judgment family was applied, per TASK-IMP-084. Score = 10/10.
End of TASK-IMP-106 audit.