The platform_version pop defaults to the schema spec so a second
validation pass over an already-validated dict cannot warn about a key
the user never set. An unparsable compile database now fails naming the
parse error and the offending output instead of blaming renamed ninja
rules. analyze-memory validates the native objdump/readelf exist and
fails by tool name rather than silently analyzing with host binutils.
The shared smoke-test helper is renamed _toolchain_components_to_test
(it serves the esp32 PlatformIO job too), and the decode-dedup state is
cleared by an autouse fixture instead of by hand.
A -n dry-run probe answers 'no work to do' without the real ninja spawn,
and running with cwd instead of -C drops the 'Entering directory' banner
on real builds too.
ninja -t compdb exits 0 with an empty list when the rule names drift, so
the compile database is now parsed and an empty result fails the build
and drops the stale file. analyze-memory refuses an unsupported
toolchain before paying for the compile. A missing size binary warns
instead of discarding an already-linked build, _parse_app_size returns
explicitly from its not-found branch, and the CI cache action asserts
the caller's install prefix matches the cached path. The esp8266
run_compile dispatch hook and copy_files early-return gain direct
tests.
A cache-arduino8266 composite action mirrors cache-esp-idf (one key
resolver, dev-writes/PR-restores) and both jobs pin
ESPHOME_ARDUINO8266_PREFIX so YAML and Python agree on the path by
construction. esp32 provides the native_toolchain_module hook, so the
shared dispatcher never names a backend and the unclaimed-native raise
loses its esp-idf carve-out; the esp8266 decode and run_compile hooks
resolve through the same seam. run_compile resolves ccache once and
threads it to the generator, env, and idedata; the compdb rule names
follow the shared kinds; the pio-options warner inlines into the driver
and derives its consumed set from the core routing constant; the
per-toolchain CI narrowing shares one body; create_components_graph is
memoized per run; the decode rate-limit drops its math sentinel.