fix: Q64 scored a point for doing nothing; Q45 failed a grade taken right after the restore

Q64's "nothing was created in namespace default" check was a bare negation,
so an untouched task scored 1/6. It now requires the Deployment to exist in
the context's namespace first.

Right after an etcd restore the API still holds the snapshot's mirror pods
and the kubelet replaces them; a grade inside that window found etcd's pod
missing and failed the health check, 8/10 for a correct restore. The check
now retries for up to a minute.

Re-verified on a throwaway cluster: both score 0 untouched and full when
solved, Q45 graded immediately after the restore.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mhxm4rsUfuE5HoytYbu2YW
This commit is contained in:
vumast3r 2026-09-22 22:24:09 -06:00
parent e1ae1876b3
commit f4f2a6bea9

View File

@ -78,7 +78,12 @@ now=$(nx "$CP" 'awk "/hostPath:/{getline; p=\$2} /name: etcd-data/{if (p) print
# the same directory name as before is fine if it was rebuilt from the snapshot after seeding # the same directory name as before is fine if it was rebuilt from the snapshot after seeding
m=$(nx "$CP" "stat -c %Y $now/member 2>/dev/null" </dev/null); [ -n "$m" ] && [ "$m" -gt "$t0" ]"""), m=$(nx "$CP" "stat -c %Y $now/member 2>/dev/null" </dev/null); [ -n "$m" ] && [ "$m" -gt "$t0" ]"""),
C("control plane healthy: etcd, apiserver, scheduler, controller-manager Running", 2, r"""j -n default cm %{cm} '{.data.proof}' | grep -q -- '-%{cm}$' || exit 1 # only once restored C("control plane healthy: etcd, apiserver, scheduler, controller-manager Running", 2, r"""j -n default cm %{cm} '{.data.proof}' | grep -q -- '-%{cm}$' || exit 1 # only once restored
for c in etcd kube-apiserver kube-scheduler kube-controller-manager; do eq "$(j -n kube-system pod -l component=$c '{.items[0].status.phase}')" Running || exit 1; done"""), # right after a restore the API holds the snapshot's mirror pods and the kubelet replaces them, so a
# grade in the first minute can find one missing - retry instead of failing on that window
for i in $(seq 1 20); do
ok=1; for c in etcd kube-apiserver kube-scheduler kube-controller-manager; do eq "$(j -n kube-system pod -l component=$c '{.items[0].status.phase}')" Running || ok=0; done
[ $ok = 1 ] && exit 0; sleep 3
done; exit 1"""),
], ],
}, },
{ {
@ -446,7 +451,7 @@ by `kubectl config view --minify`, to `{WS}/q64/ns.txt`.
"checks": [ "checks": [
C("Deployment %{dep} in %{ns} (the context's namespace), 2 available, owner=ac", 3, r"""eq "$(j -n %{ns} deploy %{dep} '{.status.availableReplicas}')" 2 && { eq "$(j -n %{ns} deploy %{dep} '{.metadata.labels.owner}')" ac || eq "$(j -n %{ns} deploy %{dep} '{.spec.template.metadata.labels.owner}')" ac; }"""), C("Deployment %{dep} in %{ns} (the context's namespace), 2 available, owner=ac", 3, r"""eq "$(j -n %{ns} deploy %{dep} '{.status.availableReplicas}')" 2 && { eq "$(j -n %{ns} deploy %{dep} '{.metadata.labels.owner}')" ac || eq "$(j -n %{ns} deploy %{dep} '{.spec.template.metadata.labels.owner}')" ac; }"""),
C("Service %{dep} port 9000 in the same namespace", 1, r"""eq "$(j -n %{ns} svc %{dep} '{.spec.ports[0].port}')" 9000"""), C("Service %{dep} port 9000 in the same namespace", 1, r"""eq "$(j -n %{ns} svc %{dep} '{.spec.ports[0].port}')" 9000"""),
C("nothing was created in namespace default by mistake", 1, r"""! $K -n default get deploy %{dep} >/dev/null 2>&1"""), C("nothing was created in namespace default by mistake", 1, r"""$K -n %{ns} get deploy %{dep} >/dev/null 2>&1 && ! $K -n default get deploy %{dep} >/dev/null 2>&1"""),
C("ns.txt has the namespace", 1, r"""eq "$(tr -d '[:space:]' < "$WS/q64/ns.txt" 2>/dev/null)" %{ns}"""), C("ns.txt has the namespace", 1, r"""eq "$(tr -d '[:space:]' < "$WS/q64/ns.txt" 2>/dev/null)" %{ns}"""),
], ],
}, },