# Claude Code Prompt: [Feature / Fix Name]

<!--
  FELHOM PROMPT TEMPLATE v1.0
  Adapted from the jarrs.eu template + harmonised with the live Felhom conventions
  (controller/agent/hub/app-catalog, Go stdlib, trunk-based, two-AI workflow).

  WHO WRITES THIS: Claude.ai (architecture/validation partner). WHO EXECUTES IT: Claude Code (CC),
  which has live SSH to the build server, the demo nodes, and felhom-pve, plus the Gitea push token.

  HOW TO USE:
  1. Copy this template into a TASK-*.md (a spec for CC to implement).
  2. Pick the TASK CLASS (§0) — it decides which sections are mandatory vs "N/A".
  3. Fill in every mandatory section. If a section doesn't apply, write "N/A — [reason]"
     (don't delete it, so CC knows it was considered).
  4. Verify all confirmed baselines and reuse line-refs against LIVE Gitea source before sending
     (cardinal rule: do not trust memory or a prior REPORT.md).
  5. Run the AUTHOR CHECKLIST at the bottom before handing the prompt to CC.

  This is NOT a RUNBOOK. TASK-*.md = "build this, push, document." RUNBOOK-*.md = "execute this
  operational procedure (incl. live validation)." If the deliverable is an operational run, write a
  RUNBOOK instead and use only §0, §1, §13, §15 of this template.
-->

---

## For the operator — what this fixes, in one page (plain language)

<!--
  MANDATORY for any M+ task and for any task carrying a STOP. Optional but encouraged below that.
  Precedent: TASK-B, TASK-C and TASK-D shipped with this section and it is why those runs needed no
  mid-flight explanation; TASK-E made it a standard block.

  WHO IT IS FOR: a technical-but-not-in-the-code reader — someone who runs the business and the
  hardware, knows what the components are, and has not read the file you are about to change.

  IT MUST SAY, in this order:
    1. WHAT BREAKS TODAY — the observable symptom, not the code defect. "Your Stop is silently
       undone on a reboot", not "shouldRecreateOnBoot ignores container state".
    2. WHAT CHANGES — the new behaviour, in the same observable terms.
    3. WHAT THE OPERATOR WILL BE ASKED TO DO — every STOP, every ruling needed, every physical
       action (flash this, press that, confirm this), and anything that is HUMAN-only. If the answer
       is "nothing", say "nothing".
    4. WHAT IS NOT AFFECTED — especially for anything touching customer data, credentials or
       recovery. "Existing codes still work" belongs here.

  RULES:
    - No jargon the ROADMAP row doesn't already explain. If a term must be introduced, define it in
      the sentence that uses it.
    - No file paths, no function names, no version numbers except the ones the operator acts on.
    - One page. If it does not fit, the task is probably two tasks.
    - Write it LAST, after the parts are settled, but place it HERE — it is what gets read first.
    - It is a summary, never the spec: it must not be the only place a requirement appears, or CC
      will implement from prose. Everything here is restated precisely in §0 onward.
-->

---

## 0. Task class & scope

<!-- Pick ONE primary class. It sets which sections are mandatory. -->

- [ ] **Implementation** — code change with unit-test coverage; build + deploy + verify. (All sections.)
- [ ] **Spike** — empirically validate an unproven mechanism BEFORE any production spec is written.
      Output is a findings doc in `felhom.eu/documentation/audits/SPIKE-<topic>-<date>.md`, not shipped
      production code. (§1, §2, §3, §4, §13-verify, §15. Skip §5-§12 unless the spike writes throwaway probes.)
- [ ] **Risky / supervised** — touches agent / golden image / provisioning / destructive disk ops, or
      anything that mutates real customer data. Spec it; implement during the supervised session itself,
      directly on `main`. Mandatory STOP point in §13. (All sections + §13 STOP is load-bearing.)
- [ ] **Runbook-style validation** — see note above; prefer a RUNBOOK-*.md.

**Repos touched** (check all — each gets its own baseline, green gate, build/deploy, and wrap-up):
- [ ] `felhom-controller` (in-guest; Docker-only; **no Proxmox creds**) — app domain
- [ ] `felhom-agent` (host; operator-tier; owns ALL Proxmox interaction)
- [ ] `felhom.eu` (`hub/`, `website/`, `documentation/`)
- [ ] `app-catalog-felhom.eu` (compose templates + `.felhom.yml`)

> Don't confuse the two ex-"controllers": **felhom-agent** (host, was `proxmox-controller`) vs this
> **felhom-controller** (in-guest, was `deploy-felhom-compose`). Host/disk/Proxmox/Cloudflare logic
> lives in the agent; the controller keeps stack/deploy/UI/app-data-backup/metrics/git-sync/notifications.

---

## 1. Confirmed baselines (anti-drift anchor — MANDATORY)

<!-- Verify each against LIVE Gitea before sending. This is what catches "CC built on a stale tree".
     curl -H "Authorization: token $TOKEN" \
       "https://gitea.dooplex.hu/api/v1/repos/admin/<repo>/commits?sha=main&limit=1"
     and read the version from the source of truth (ldflags var / VERSION / latest CHANGELOG entry). -->

| Repo | `main` @ commit | Current version | → Target version |
|------|-----------------|-----------------|------------------|
| felhom-controller | `<hash>` | `v0.XX.0` | `v0.XX+1.0` |
| felhom-agent | `<hash>` | `v0.YY.0` | `v0.YY+1.0` |
| felhom.eu (hub) | `<hash>` | `v0.ZZ.0` | `v0.ZZ+1.0` |

**An unpushed change does not exist** for validation or deployment. CC commits directly to `main`
(trunk-based — **no feature/fix branches**). If a change can't be cleanly shipped, **revert + report**;
never park it on a branch.

---

## 2. Overview

<!-- 3–5 sentences. What this implements, the user-visible outcome when done, which architecture/spike
  doc it corresponds to, and which slice/phase it belongs to. Orientation, not specification. -->

---

## 3. Spike-first gate

<!-- Answer honestly. If this touches a mechanism whose behaviour has NOT been empirically proven
  (a new external API, an undocumented Proxmox/PBS quirk, a filesystem/mount edge), this is a SPIKE,
  not an implementation. The PBS spike caught `ignore-verified=true`, the node-name-from-UPID
  requirement, and the dual privsep+token grant BEFORE any code — that is the bar. -->

- Does this rely on any unvalidated mechanism? **yes / no**
- If yes: is it already validated in a spike doc? Cite it: `felhom.eu/documentation/audits/SPIKE-...`.
- If yes and not validated: **STOP — switch task class to Spike.** Do not spec production code on
  assumptions.

---

## 4. Read these files first

<!-- Order matters: workspace/repo conventions first, then architecture, then the exact source.
  Be explicit about WHY each matters. -->

1. `/mnt/5_hdd/felhom.eu/git/CLAUDE.md` — workspace orientation (the felhom system, shared
   conventions, access). Versioned copy: `felhom.eu/documentation/runbooks/workspace-CLAUDE.md`.
2. `<repo>/CLAUDE.md` — repo build/deploy, code-quality rules, trunk-based + live-validation rules.
3. `<repo>/CONTEXT.md` — current project state / decisions / roadmap.
4. `felhom.eu/documentation/architecture/02-controller-module-map.md` — KEEP/PORT/DELETE/MODIFY
   per-package classification. **Read before touching `backup/`, `storage/`, `system/`, `config/`.**
5. `felhom.eu/documentation/controller/<feature>.md` — code-verified feature docs (authoritative; match
   code, not summaries, if they drift).
6. `controller/README.md` (or `felhom-agent/README.md`) — module map, feature reference, REST API.
7. [exact source file(s) to modify] — [why it's relevant].
8. [exact source file(s) to depend on] — [why it's relevant].

---

## 5. Existing functions / helpers to reuse (MUST use — do NOT reinvent)

<!-- For Go: cite file + exported symbol + short signature. Verify EVERY symbol against live source
  (read the file; don't write names from memory — they drift). Line numbers are LANDMARKS only:
  the bundled files CC reads are not the source files, so reference by symbol/landmark and tell CC to
  reconfirm the line. If a helper must change to support this task, say "Yes — [exact change]" in
  Modify? — that becomes an explicit task in a Part below, not an implicit assumption.

  The forbidden reuse: e.g. "do NOT reuse rsyncMirror (tier2.go) — it has --delete". Name the trap. -->

| Symbol | File (landmark) | Signature / use | Modify? |
|--------|-----------------|-----------------|---------|
| `Manager.StopStack` | `internal/stacks/manager.go` (~L682) | `StopStack(name string) error` — idempotent | No |
| `Manager.RedeployFromEnv` | `internal/stacks/deploy.go` (~L478) | writes app.yaml then `compose up -d` + post-start status | No |
| `appbackup.AppDataDir` | `internal/.../paths.go` | namespace+app → data dir | No |
| `writeDiskJSON` | `internal/.../agent_disk_handlers.go` | JSON envelope for disk endpoints | No |
| [helper that needs a change] | `path/file.go` | `Func(args)` | **Yes — add `intent` param; gate on `IntentEnrolled`** |

**Do NOT reuse:** [name the dangerous-lookalike + why], e.g. `rsyncMirror` (has `--delete`).

---

## 6. Pattern references (copy structure from these canonical files)

<!-- For every NEW file type this task creates, point to the ONE canonical file to copy from. -->

| Pattern | Canonical file | Key traits to copy |
|---------|----------------|--------------------|
| REST handler | `internal/api/router.go` + a sibling handler | stdlib `net/http`, JSON envelope, error logging |
| Local-API disk handler | `internal/localapi/disks.go` (`handleDiskEject`) | `withGuest`, `scopedFromBody`, role gate, fail-safe-to-protected |
| Scheduler job | `internal/.../scheduler` | register + skip-if-running, graceful shutdown |
| Crash-safe journal | `internal/stacks/backup.go` | journal-before-mutate, atomic tmp+fsync+rename, `Recover` on startup |
| Unit test | `internal/.../*_test.go` (a recent non-hollow one) | `t.TempDir()`, fakes/seams, effect assertions |
| HTML template | `internal/web/templates/*.html` | Hungarian UI, Go template funcs, no inline secrets |

---

## 7. Integration scenarios (must pass)

<!-- WRITE THESE BEFORE THE IMPLEMENTATION SECTIONS. They are the acceptance criteria.
  Given/When/Then with concrete actors and exact counts/states. Always include the WRONG case.
  EVERY scenario here MUST have a corresponding test in §11/Tests. -->

### Scenario A — [happy path]
```
Given: [concrete state]
When:  [exact endpoint / CC action]
Then:
  - [effect 1 — exact value/state]
  - [effect 2]
  - [the WRONG outcome this must NOT produce]
```

### Scenario B — [alternative / role / mode]
```
Given: [what differs from A]
When:  [action]
Then:  [how outcomes differ and WHY]
```

### Scenario C — [error / boundary / security gate]
```
Given: [bad input / unauthorised actor / data-bearing device]
When:  [action that must be refused]
Then:  [exact refusal — HTTP status, error, and the proven non-effect, e.g. "mkfs NOT called"]
```

---

## 8. Edge cases & deduplication rules

<!-- Explicit rules for overlapping concerns: "When X and Y both apply, the result is Z — not X+Y."
  Use a truth table if >2 branches. (E.g. conflict-merge: target absent → copy; present+identical →
  skip; present+differs → write lowest-free (N), never overwrite.) -->

| Condition A | Condition B | Result |
|-------------|-------------|--------|
|             |             |        |

---

## 9. Strict rules

<!-- Earned through bugs. Copy verbatim; document any per-task exception. -->

1. **Green gate (Go):** after **every commit/phase**, in each touched repo:
   `go build ./... && go vet ./... && go test ./...` — all green before proceeding. The build IS the
   typecheck; do not accumulate compile errors.
2. **Minimal changes:** build only what's listed. No "while I'm here" refactors. Note anything worth
   fixing under "Observations" (§15) — don't act on it.
3. **No silent failures:** never swallow a parse/exec error — log it. Check a subprocess's **own** exit
   code; never pipe in a way that hides a 127. (The silent `.felhom.yml` quoting bug + the spike's
   exit-swallow lesson.)
4. **Secrets safety:** log env var **keys**, never values. **Never write secrets** (tokens, passwords,
   keys) into `CHANGELOG.md`, `REPORT.md`, or any committed file — reference as "stored out-of-band".
5. **Line numbers are landmarks:** reference code by symbol/landmark; reconfirm the line in the real
   source before editing (bundled files ≠ source files).
6. **Trunk-based:** commit directly to `main`. No branches. Can't ship cleanly → revert + report.
7. **Version discipline:** never `:latest`; bump the version on every task; one CHANGELOG entry per
   shippable change; **overwrite** REPORT.md.
8. **Coding standards:** follow `<repo>/CLAUDE.md` (cross-cutting) and the feature doc / README for
   domain patterns.

---

## 10. Non-hollow test discipline (MANDATORY for any correctness/security fix)

<!-- The Felhom signature. A test that only asserts "no error" is hollow. -->

- **Assert the effect happened**, not just absence of error. Security example: prove `mkfs` was NOT
  called on a data-bearing device by inspecting the device/fake state — not by trusting the caller.
- **Companion red-proof:** for every correctness fix, write the test so it **FAILS on the pre-fix /
  trivial implementation**. Demonstrate this: run the mutation (or guard-removed shape), confirm the
  test fails, revert. State the result in §15.
- **FS work** uses `t.TempDir()`; **orchestration** uses fakes/seams (introduce a small `stackOps` /
  `copier` interface so tests don't shell out to docker/rsync).
- **Generation/idempotency:** assert the negative (e.g. "fetch count does NOT increment on an
  unchanged heartbeat"; "a re-run finds its own prior `(N)` and adds no `(1)(1)`").
- **Seam discipline — every seam added gets ONE test through the PRODUCTION wiring path.** An
  injected-seam test proves the component, never the caller. Three shipped defects in three days
  make this non-negotiable: controller v0.154.0 (the wizard read a flag the handler never sets),
  agent v0.91.0 (`main.go` never called `SetAuthSink`, so the whole auth-honesty leg was inert), and
  agent v0.92.0 (the watchdog had no sudoers grant for three of its four probes). **Every one of
  them was fully green.** Where the caller is `func main()` and cannot be invoked from a test, walk
  its AST for the call — and note that a `strings.Contains` on the source is NOT sufficient: a
  commented-out call still contains the string, which is how the controller's first version of that
  test passed its own red-proof (2026-07-21).

---

## Part 1: [Foundation / engine]

### 1.1 [Task]

**File(s):** `path/file.go`
**Problem:** [what's wrong / what to build, and why]
**DO:** [explicit positive instructions; tricky code snippets only — CC fills the obvious parts]
**DO NOT:** [the specific anti-pattern for THIS task]
**Crash-safety (if stateful):** journal-before-mutate; atomic tmp+fsync+rename; `Recover` on startup;
guaranteed cleanup via `defer` **for graceful exits only** — a `defer` does NOT run on SIGKILL, so a
crash-safe cleanup needs an on-disk marker plus a startup `Recover()` (Campaign 8 fault 10 proved
this on live hardware); single-flight mutex; `ListLXC`-style ground truth in recovery.

**Green gate:** `go build ./... && go vet ./... && go test ./internal/<pkg>/`

---

## Part 2: [Core logic / external surface]

### 2.1 [Task]

**Phase order (risky surfaces):** Phase A structural → validate → Phase B security/external surface.

**Green gate:** full `go test ./...`

---

## Part 3: [Web / UI — if touched]

### 3.1 [Task]

<!-- Felhom UI is Hungarian, adult tone, minimal emoji (keep UI clean/professional). Specify the exact
  strings. Reuse template funcs (stateColor/stateLabel/isOperational/logoURL/...). Progress panels:
  reuse the deploy 3-step + format-status poll pattern. -->

**Hungarian strings:** "[exact copy]" — e.g. "Adatok másolása: <app> (X% — Y/Z GB)…".

**Green gate:** `go build ./...` + `go test ./...`

---

## Part N: Documentation & versioning

### N.1 CHANGELOG.md (each touched repo)
Cumulative, **newest entry on top**. New version number. Cite the files/commits for each item.

### N.2 REPORT.md (each touched repo) — **OVERWRITE**
Most-recent implementation only (not cumulative). MUST contain: confirmed baselines, per-commit
hashes, per-test results, deployed versions, and an explicit **"NOT yet live-validated — awaiting
supervised [Bx]"** list. No secrets.

### N.3 CONTEXT.md
Decisions made, architectural state, what's next.

### N.4 README / architecture docs
`<repo>/README.md` if architecture/features changed; authoritative architecture/feature docs in
`felhom.eu/documentation/{architecture,controller}/`. Spikes/audits → `felhom.eu/documentation/audits/`.

### N.5 The coupling rule — FOUR artifacts, same session (end-of-session checklist)
If the task **changed what the platform can do** (new/removed capability, a capability moved status,
or **what is open changed**), update **all four** in the SAME session:
- **`architecture/00-capability-map.md`** — add/adjust the affected *scenario* row with the correct
  **status** (PROVEN-LIVE requires an `audits/`|`tests/` citation; else IMPLEMENTED/PARTIAL) and an
  evidence citation. A leg not exercised live → PARTIAL/IMPLEMENTED with a note saying which leg and
  a `→ R-n` pointer, never PROVEN-LIVE.
- **`backlog/ROADMAP.md`** — add any new open work / deferred legs as an item (next free `R-n`),
  collapse a now-shipped item to its one-liner + version, and honor the **coupling rule** (every
  roadmap item names the map row it flips; every map gap row points back by ID). Parked sub-features
  (e.g. an alternative transport, an agent-plane leg) go as a note under the owning arc's item.
- **the owning `architecture/*.md`** — ruled as **S-1** in `CONTEXT.md` (2026-07-26, R-81): any task
  that changes an **architectural contract** (tiers, targets, cadences, trust boundaries) updates the
  owning design doc in the same session. It was ruled but never written here, in the template CC
  actually reads — so it bound nobody. Now it does.
- **`backlog/OPEN-ITEMS.md`** — the register, and the single source of truth for open work. A task
  that changes what is open without touching it re-creates exactly the thread-loss the register was
  built to solve: `REPORT.md` is overwritten every session, so nothing durable may live only there.

**Report which `OPEN-ITEMS.md` rows the task opened, closed or re-ranked** (§15). Every row carries
an owner — a row nobody owns is how items got lost in the first place.

### N.6 Website version bump (if controller/hub version is shown on the site).

---

## 11. Tests

<!-- Numbered, mapping DIRECTLY to §7 scenarios. Every scenario (incl. error) gets ≥1 test.
  Each correctness/security test gets the §10 companion red-proof. -->

### Test Group A — [Scenario A]
```
- setup (t.TempDir / fakes)
- action (the exact call)
- assert (effects, exact values/counts)
- companion: [mutation that makes it fail on pre-fix code]
```

### Test Group B — [Scenario B]
### Test Group C — [Scenario C — error/security gate]

---

## 12. What NOT to do

<!-- Concrete temptations for THIS task, not "don't add features". -->

- Do NOT [specific out-of-scope thing CC might build].
- Do NOT [**the forbidden ACT**, and **its reason**: e.g. "modify the operator-signed
  `DecommissionExecutor` — it is the signature boundary"]. **Fence the act, not the object.** A bare
  "do not touch X" is read as covering every act on X, including ones nobody meant to restrict — that
  is how "do not re-target demo-hp's backup target" became "do not use demo-hp at all", which pushed a
  destructive drill onto the one machine holding the recovery chain. State the reason too: a rule whose
  reason is recorded can be correctly narrowed later, and one without it becomes permanent by default.
- Do NOT reuse [the dangerous lookalike from §5].
- Do NOT refactor nearby code, change passing tests, or create a branch.
- Do NOT add "Co-Authored by..." anywhere

---

## 13. Build / deploy / STOP

<!-- Per touched repo. Real commands. CC runs ON DooPlex — builds are LOCAL, no SSH wrapper. -->

**Clean-tree gate first:** `git status --porcelain` empty AND `HEAD` == `origin/main` in the repo
being built. An unpushed change does not exist.

**If the task needs a machine to break — NAME IT.** A drill, destructive test or throwaway VM gets an
explicit target: *"run this on demo-hp"*. Do not leave it to be inferred from the prohibition list;
listing only what is off-limits leaves the most valuable unfenced machine as the residual choice, which
is exactly how a drill landed on DooPlex. Tiers and per-machine permitted/care/forbidden:
[`runbooks/target-selection.md`](runbooks/target-selection.md).

**Controller** (local build on DooPlex → guest via golden/bootstrap):
```bash
FELHOM_ROOT=/mnt/5_hdd/felhom.eu
# build + push
cd $FELHOM_ROOT/build/felhom-controller && git -C $FELHOM_ROOT/git/felhom-controller pull && ./build.sh <VER> --push
# deploy to guest (golden/bootstrap): docker pull → write /etc/felhom-controller-image → restart bootstrap svc
# verify:
ssh felhom-pve "pct exec 9201 -- docker ps --filter name=felhom-controller --format '{{.Image}} {{.Status}}'"
```

**Agent** (build locally, `scp /tmp/felhom-agent-<VER> felhom-pve:/tmp/` — one hop; deploy to
`felhom-pve`: backup prior binary, replace, restart service; verify clean restart — e.g.
`ReassertGuestBinds` does not rebind a non-`enrolled` drive).

**Hub** (`felhom.eu/hub/`): build + push locally, then bump `manifests/hub.yaml`'s `image:` tag in
git and do a deliberate ArgoCD sync — **never `kubectl set image`** (auto-sync is OFF and any
imperative change is reverted on the next sync). Verify Synced/Healthy + rollout + image + logs.

**Live validation rule:** if validating a user-facing feature, exercise the **real server pipeline**
(connect → enroll → deploy), or invoke the **exact endpoint the UI invokes** (acceptable proxy — no
server logic skipped). **Do NOT** hand-set state via raw agent attach (the F9 bypass). Browser
automation is **NOT available** on DooPlex — endpoint-level is the standard method; say which was used.

**STOP point (risky/supervised tasks):** build + unit-test + build/deploy images, but **do NOT run a
live destructive op or migrate real customer data** — that is the supervised [Bx] step. Throwaway
marker dirs under a scratch `/mnt` path are OK only if they touch no enrolled customer data.

**Teardown.** A run that provisions anything owns its removal. Three layers, and the third is the one
that gets missed:

1. **The machine** — the VM or guest and its volumes, deleted.
2. **The host** — `pvesm status` before and after, and the space actually returned.
3. **The hub** — the customer or appliance record the run created. State its disposition
   **explicitly**: deleted; or retained as a fixture **with the reason**; or blocked by the
   ONLINE→DOWN delete gate **with the command recorded for later**. Silence is how `drill-r50` became
   both a blocked customer and the only drift fixture.

**Precedent: three drills, three orphaned customers** — `drill-r50`, `sess-c`, `sess-d`. `sess-c` was
not recorded by its own report, so the record said the teardown was clean when it was not. Layers 1 and
2 are the ones that get remembered because they are visible on the box; layer 3 is invisible from there
and has been missed every time.

Which machine to provision on in the first place: **`documentation/runbooks/target-selection.md`**.

---

## 14. Implementation order

```
Phase 1: [Part 1]            → go build ./... && go vet ./... && go test ./internal/<pkg>/
Phase 2: [Part 2]            → full go test ./...
Phase 3: [Part 3 — UI]       → go build ./... && go test ./...
Phase N-1: [Tests]           → full go test ./... (all green)
Phase N:   [Build/deploy/verify + docs + push to main]
```

---

## 15. Final verification & deliverables

<!-- CC runs this after all phases. This report is what Claude.ai validates against pushed Gitea
  source (file:line) — the cardinal rule. Make it checkable. -->

Run, per touched repo: `go build ./... && go vet ./... && go test ./...`

Report MUST include:
1. **Confirmed baselines** used (repo @ hash, version).
2. **Files created / modified** (paths).
3. **Per-commit hashes** pushed to `main`.
4. **Per-test results** (name → pass/fail) + the §10 companion red-proof outcomes.
5. **Test count before / after**; all green (or list failures).
6. **Deployed versions** + `docker ps` / agent-service / hub-pod verification output.
7. **NOT yet live-validated — awaiting supervised [Bx]:** explicit list (the real
   put-data → operate → integrity flow).
8. **Evidence copied off BEFORE each revert** — for every phase that ran on a machine, the logs were
   pulled to the evidence directory **at the end of that phase**, before any revert, snapshot restore
   or teardown, **including the intermediate ones**. *The intermediate revert is the one that gets
   forgotten: two sessions lost a phase's logs to a mid-run revert to `virgin` on 2026-08-12 and
   2026-08-13 — same machine, same point, three days apart (R-320).* **If a phase's evidence is
   already gone, the report says so plainly and the finding is REPRODUCED independently** — that is the
   expectation, not an improvisation. A quotation read live and no longer re-readable is named as such.
9. **Teardown evidence — all three §13 layers**, if the run provisioned anything: the machine deleted,
   `pvesm status` before/after with the space returned, and the **hub-side record's disposition named**
   (deleted / retained-with-reason / gate-blocked-with-the-command). A run that provisioned nothing says
   so. "Teardown clean" without layer 3 is not a report — it is the `sess-c` failure.
9. **Observations:** out-of-scope items noticed — documented, NOT acted on.

---

<!--
========================================================================
AUTHOR CHECKLIST (for Claude.ai — verify before handing to CC)
========================================================================

| # | Check | Prevents |
|---|-------|----------|
| 1 | Task class picked; mandatory sections filled (rest "N/A — reason")?         | Bloated small tasks / under-covered risky ones |
| 2 | Confirmed baselines verified against LIVE Gitea (hash + version), not memory? | CC builds on a stale tree |
| 3 | Spike-first gate answered; unvalidated mechanism → switched to Spike?        | Spec'ing production code on assumptions |
| 4 | Every reuse symbol verified against live source; line-refs marked landmark?  | Wrong method names; line drift |
| 5 | Every helper marked "Modify? Yes" has an explicit Part task?                  | Helper change treated as afterthought |
| 6 | Dangerous-lookalike reuse explicitly forbidden (the trap named)?             | `--delete` / over-broad reuse bug |
| 7 | Integration scenarios written BEFORE implementation, incl. the WRONG case?    | CC reads top-down; ambiguous acceptance |
| 8 | Every scenario (incl. error/security) has ≥1 test?                            | Untested boundaries |
| 9 | Every correctness/security fix has a non-hollow test + companion red-proof?   | Hollow "no error" tests; silent regressions |
| 10| Green gate stated per repo per phase (build && vet && test)?                  | Accumulated compile/test debt |
| 11| Secrets-safety: no secret written to committed files; keys-not-values in logs?| Leaked credentials in CHANGELOG/REPORT/logs |
| 12| Trunk-based: no branch instructions; revert-and-report escape hatch stated?  | Work parked on a branch |
| 13| Build/deploy commands correct for each repo (controller golden / agent / hub)?| Failed or wrong deploy |
| 14| STOP point explicit for risky/supervised; live-validation hits real pipeline?| Destructive op run unsupervised; F9 bypass |
| 15| Doc routing correct (CHANGELOG cumulative, REPORT overwrite, CONTEXT, README, documentation/)? | Doc drift / cumulative REPORT |
| 15b| Capability changed → `00-capability-map.md` row + status/evidence updated AND `backlog/ROADMAP.md` item added/collapsed (coupling rule)? | Capability map goes stale; deferred legs lost |
| 16| UI strings Hungarian + adult tone + minimal emoji specified?                  | English/placeholder UI leaking to customers |
| 17| §15 report format demanded so the result is validatable against Gitea?       | Unverifiable "done" claims (cardinal rule) |

If any check fails, fix the prompt before sending.
========================================================================
-->