8f21873d45
Co-authored-by: nova28 <17953305+nova28@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
111 lines
4.1 KiB
Markdown
111 lines
4.1 KiB
Markdown
---
|
|
spec: docs/specs/executors/requirements/remote-task-directory-reclamation.md
|
|
system_design: docs/specs/executors/system-design/remote-task-directory-reclamation.md
|
|
created: 2026-08-24
|
|
status: done
|
|
---
|
|
|
|
# Implementation Plan: SSH Remote Task-Directory Reclamation
|
|
|
|
## Overview
|
|
|
|
Build the v2 housekeeper bottom-up, so that the safety machinery exists and is
|
|
proven before anything can call it. Wave 1 delivers the two independent
|
|
primitives — the read-only safety probe plus guarded removal in the `lifecycle`
|
|
package, and the per-profile opt-in plumbing in `orchestrator/executor` — neither
|
|
of which can delete anything on its own. Wave 2 wires them into the durable
|
|
cleanup job, which is the only caller and the point at which removal becomes
|
|
reachable. Wave 3 adds the settings UI, the ADR, and the documentation
|
|
corrections.
|
|
|
|
The order is deliberate: task 01 is written and tested with no caller, so a
|
|
mistake in the probe cannot reach a real host through a half-built job phase.
|
|
|
|
## Safety constraint on all tasks
|
|
|
|
**No test may delete anything outside a `t.TempDir()`.** The removal path is
|
|
exercised through the `sshRemoteRunner` interface with recorded command outputs,
|
|
or against a temporary directory. No test creates, targets, or removes a path
|
|
under a real Kandev workspace root, and no test runs `rm -rf` against a path
|
|
derived from the developer's environment. A test that deletes its own workspace
|
|
destroys the run that produced it.
|
|
|
|
---
|
|
|
|
## Waves
|
|
|
|
| Wave | Tasks | Parallel-safe |
|
|
| --- | --- | --- |
|
|
| 1 | 01, 02 | Yes — disjoint packages |
|
|
| 2 | 03 | No — depends on 01 and 02 |
|
|
| 3 | 04, 05 | Yes — disjoint (web / docs) |
|
|
|
|
---
|
|
|
|
## Backend
|
|
|
|
### Task 01 — Probe and guarded removal (`lifecycle`)
|
|
|
|
New `executor_ssh_reclaim.go` with `SSHTaskDirReclaimer`, the four-probe safety
|
|
table, the path-shape guard, and `rm -rf` behind a `sshRemoteRunner` seam. Pure
|
|
verdict logic, no callers.
|
|
|
|
### Task 02 — Per-profile opt-in (`orchestrator/executor`, `lifecycle`)
|
|
|
|
`MetadataKeySSHReclaimTaskDir`, entry in `profileConfigAuthoritativeKeys` and
|
|
`persistentMetadataKeys`. Proves a task-supplied value cannot enable the feature.
|
|
|
|
### Task 03 — Cleanup-job phase (`task/service`)
|
|
|
|
Snapshot capture, ownership resolution, invocation, and the skip-versus-error
|
|
outcome folding. This is where the regression coverage for removal-on-terminal
|
|
and preservation-on-ordinary-stop lands.
|
|
|
|
---
|
|
|
|
## Frontend
|
|
|
|
### Task 04 — Settings toggle
|
|
|
|
Per-profile switch in the SSH executor profile settings with blast-radius copy,
|
|
routed through `t()` and translated into all five locales.
|
|
|
|
---
|
|
|
|
## Documentation and decisions
|
|
|
|
### Task 05 — ADR and doc corrections
|
|
|
|
ADR for the opt-in default and the cleanup-job placement;
|
|
`docs/public/feature-status.md` SSH row updated to describe shipped behavior.
|
|
|
|
`apps/backend/AGENTS.md` and the `Out of scope (v1)` item in
|
|
`docs/specs/executors/system-design/ssh-executor.md` is corrected as part of this design package
|
|
rather than at ship time — the first is a present-tense factual error about
|
|
today's code, and the second is the specification boundary this package moves.
|
|
|
|
---
|
|
|
|
## Task checklist
|
|
|
|
- [x] 01 — `task-01-reclaim-probe-and-removal.md`
|
|
- [x] 02 — `task-02-profile-opt-in.md`
|
|
- [x] 03 — `task-03-cleanup-job-phase.md`
|
|
- [x] 04 — `task-04-settings-toggle.md`
|
|
- [x] 05 — `task-05-adr-and-docs.md`
|
|
|
|
## Risks
|
|
|
|
- **The probe is the whole feature.** A false "safe" verdict is silent,
|
|
irreversible data loss on a machine Kandev does not own. Task 01's verdict
|
|
table must be exhaustive over probe-failure modes, and every unknown must
|
|
resolve to skip.
|
|
- **Ownership signal coverage.** The environment-ownership check is the existing
|
|
precedent, but a parent task whose `executor_running` rows were pruned while
|
|
its directory survives would not be seen by the row-level check. The
|
|
environment check is the primary defence and the row check is secondary; task
|
|
03 must cover the `inherit_parent` case directly.
|
|
- **Archive is reversible, removal is not.** An unarchived task re-materializes
|
|
its checkout. That is acceptable under an opt-in setting but must be stated in
|
|
the settings copy (task 04).
|