---
id: w1/m19/t009
title: Full acceptance: verify-elastic on prod, CI green e2e, port scan, close w1/014
worker: worker1
status: todo
estimate: 45m
depends_on: [w1/m19/t007, w1/m19/t008, w1/m19/t011]
---

## Objective

Prove the milestone's DoD line by line, then retire the incident note and unblock m3's closeout.

## Context

- scripts/verify-elastic.sh must first be REWRITTEN by t011 (dependency flipped 2026-07-11 — the script still assumes the dead mgmt/workload pair, `head -1` MD selection now picks the tainted platform pool): pool-parameterized, tenant-label node filter, self-managed context. Before any elastic run, annotate the app-bearing tenant node `cluster-autoscaler.kubernetes.io/scale-down-disabled=true` — app images are node-local ctr imports; a scale-down strands them.
- The m3/t008 conditions: prod kube-scheduler runs --config=/etc/kubernetes/scheduler-config.yaml; verify pack behavior comes from the live check.

## Steps

1. Run verify-elastic.sh (tenant pool); re-run app-cluster.yml twice for idempotence; 24h CSR-event watch (`kubectl get events -A | grep CSRValidationFailed` empty); external port scan of one node public IP (only :22) and the LB fronts (80/443, 6443); OpenBao 3/3; KCP conditions clean.
2. ~~w1/014 resolution note + m3 closeout~~ _done 2026-07-11 ahead of schedule: resolution note appended to `w1/done/014.md`; m3 closed and moved to `w1/done/m3/` (its t008 conditions were met by the rebuild)._
3. ~~Update docs/rearchitecture.md status~~ n/a — doc absorbed into docs/ADR002-architecture.md and deleted 2026-07-11; record acceptance evidence here instead.

## Files

- scripts/verify-elastic.sh (env only)
- .pm/w1/014.md -> .pm/w1/done/014.md
- .pm/w1/m3/ closeout via its t008
- docs/ADR002-architecture.md (§The production substrate — flip the interim-shape note when the target lands)

## Acceptance criteria

- [ ] Every DoD bullet in the m19 README checked with evidence links/output.
- [ ] w1/014 in done/ with resolution note; m3 fully in w1/done/m3/.

## Pre-verified evidence (2026-07-11, post-m19.1, ahead of the quota-gated remainder)

- **Port scan ✓** — node public IP `46.225.152.95` (tenant worker): `:22` open only; `:6443/:10250/:2379/:8472/:30080/:5000` all closed/filtered (label-selector firewall live).
- **kube-scheduler `--config` ✓** — prod scheduler runs `--config=/etc/kubernetes/scheduler-config.yaml` (the last m3/t008 leg, verified on the rebuilt CP).
- **Both LBs private-net ✓** — `bex-kube-apiserver` (targets=1) and `bex-traefik` (targets=3) both attached to the private network, targets by private IP.
- **CI green e2e ✓** — app-cluster.yml + deploy.yml both green multiple consecutive runs on the self-managed path (2026-07-11, incl. two post-simplify runs).
- **Self-managed substrate ✓** — `scripts/verify-substrate.sh` ALL PASS (mgmt-free access, in-cluster machines+KCP, CAPI on CP, in-cluster autoscaler, no bex-infra).
- **hcloudNetwork ✓** — network `bex` 10.10.0.0/16 CAPH-owned (label `caph-cluster-bex: owned`), every machine attached at creation.
- Remaining (quota-gated, `.pm/FUTURE-MAYBE.md`): 3 CP tainted quorum, openbao-1 unseal → 3/3 (first prod init done 2026-07-11 on a 2-member raft), verify-elastic three phases on the tenant pool, 24h CSR-event window, idempotence double-run, then w1/014 resolution note + m3 closeout + flip ADR002-architecture.md's interim-shape note.

## Out of scope

- w1/008 (per-service autoscaling) - now unblocked, separate milestone.
