@@ -9,6 +9,103 @@ The format is based on the regulated environment requirements:
99
1010---
1111
12+ ## [ 2026-06-24 10:30] - Idempotency sweep: 409 AlreadyExists / duplicate finalizers no longer Error the ScheduledMachine
13+
14+ ** Author:** Erick Bourgeois
15+
16+ ### Changed
17+ - ` src/reconcilers/helpers.rs ` (` create_dynamic_resource ` ): treat a ` 409 AlreadyExists `
18+ from ` api.create(...) ` as success instead of propagating it. The bootstrap config,
19+ infrastructure object, and CAPI Machine are all created through this helper; a prior
20+ reconcile having created them IS the desired state.
21+ - ` src/reconcilers/helpers.rs ` (` add_finalizer ` ): only append our finalizer if it isn't
22+ already present — a double-call can no longer write a duplicate (which would wedge GC).
23+ - ` src/reconcilers/helpers_tests.rs ` : +3 unit tests (create 409 → Ok; create 500 still
24+ propagates; add_finalizer writes exactly one copy).
25+ - Audited the rest of the codebase for idempotency and confirmed it already holds: the
26+ only other ` .create() ` is a ` SelfSubjectAccessReview ` (a virtual auth check, never
27+ 409s); all ` .delete() ` sites swallow 404; the kata ConfigMap uses ` Patch::Apply ` (SSA);
28+ Events go through the kube ` recorder ` ; status/spec writes use ` Patch::Merge ` /` Apply ` .
29+
30+ ### Why
31+ On every reconcile after the first, ` add_machine_to_cluster ` re-issues the create and
32+ got ` 409 AlreadyExists ` (e.g. ` k0sworkerconfigs "…" already exists ` ). That bubbled up as
33+ ` MachineCreationFailed ` , flipping the ScheduledMachine into the ** Error** phase — which
34+ skips ALL Active-phase work, including node-taint reconciliation. On the k0smotron
35+ workshop tier this presented as ** Flag 1 (worker joins) passing but Flag 2 (the Node
36+ carries the spot taint) never happening** : the SM was wedged in Error, so it never ran
37+ ` handle_active_phase ` . Idempotent create is standard controller behavior and fixes it.
38+
39+ ### Impact
40+ - [ ] Breaking change
41+ - [x] Requires cluster rollout
42+ - [ ] Config change only
43+ - [ ] Documentation only
44+
45+ ## [ 2026-06-24 03:10] - Fix Mermaid flow diagrams broken by special characters
46+
47+ ** Author:** Erick Bourgeois
48+
49+ ### Changed
50+ - ` docs/architecture/calm/architecture.json ` : escaped Mermaid-hostile characters in
51+ three flow transition descriptions using Mermaid entity codes (which render as the
52+ literal characters):
53+ - ` flow-emergency-reclaim ` t1: ` reclaim-requested="true" ` → ` reclaim-requested=#quot;true#quot; ` .
54+ The embedded double quotes terminated the Mermaid label string early, causing a parse
55+ error that left the ** Emergency Reclaim** diagram blank on the docs site.
56+ - ` flow-kata-config-delivery ` t2: ` /etc/5spot/kata-config/<key> ` → ` …/#lt;key#gt; ` .
57+ - ` flow-kata-config-delivery ` t5: ` restart <restartService> ` → ` restart #lt;restartService#gt; ` .
58+ Raw ` <…> ` placeholders were parsed as HTML tags and silently dropped from the rendered label.
59+ - ` docs/src/architecture/flows.md ` : regenerated via ` make calm-diagrams ` (auto-generated;
60+ not hand-edited).
61+ - ` docs/src/concepts/kata-config-delivery.md ` : hand-written ` sequenceDiagram ` — replaced a
62+ ` ; ` with ` , ` inside a ` Note over Agent,Host: … ` label. Mermaid treats ` ; ` as a statement
63+ separator even inside note text, so it split the note mid-string and failed the whole
64+ diagram to parse.
65+
66+ ### Why
67+ The ` flows.md.hbs ` template emits transition descriptions verbatim into ` flowchart ` node
68+ labels (` t1["…"] ` ). Mermaid cannot contain an unescaped ` " ` inside a quoted label, and
69+ treats ` <…> ` as HTML — so these characters either broke parsing (Emergency Reclaim) or
70+ ate label text (Kata Config Delivery). Fixing at the source-of-truth ` architecture.json `
71+ keeps the diagrams correct after every regeneration. The ` phase -> … ` arrows in other
72+ flows contain only ` > ` and render fine, so they were left unchanged.
73+
74+ ### Impact
75+ - [ ] Breaking change
76+ - [ ] Requires cluster rollout
77+ - [ ] Config change only
78+ - [x] Documentation only
79+
80+ ---
81+
82+ ## [ 2026-06-24 02:30] - Surface the real cause of child-cluster connection failures (error_chain)
83+
84+ ** Author:** Erick Bourgeois
85+
86+ ### Changed
87+ - ` src/reconcilers/helpers.rs ` : new ` error_chain(&dyn Error) ` helper that flattens an
88+ error's ` source() ` chain into one string, and wired it into all six child-cluster
89+ failure logs (taint GET/PATCH/reconcile, kata clear/stamp). These previously logged
90+ only the terse top-level ` Display ` ("client error (Connect)"), hiding the real cause.
91+ - ` src/reconcilers/helpers_tests.rs ` : +2 unit tests for ` error_chain ` (multi-level
92+ source chain; single error with no source).
93+
94+ ### Why
95+ A k0smotron-hosted control plane (workshop k0smotron tier) exposes a self-signed API
96+ server cert that ** rustls** (5-Spot's TLS backend, kube 3.1 default) rejects where
97+ OpenSSL/curl ` -k ` accept it — so 5-Spot's child client fails to taint/drain the worker
98+ Node with ` client error (Connect) ` , with no visible cause. Logging the full chain makes
99+ the exact rustls reason (unknown issuer / SAN mismatch / unsupported signature) visible
100+ so the fix can target it (a proper cert, ` tls_server_name ` , or ` insecure-skip-tls-verify `
101+ on the child kubeconfig — kube already honors the latter via ` Config::accept_invalid_certs ` ).
102+
103+ ### Impact
104+ - [ ] Breaking change
105+ - [ ] Requires cluster rollout
106+ - [ ] Config change only
107+ - [x] Diagnostics only (no behavior change)
108+
12109## [ 2026-06-23 11:45] - Ship the spot-schedule provider binaries in the image (ADR 0009 providers were unrunnable)
13110
14111** Author:** Erick Bourgeois
0 commit comments