Namespaces were shared across features: `settings` was written by core, the
panel and touch, and `input` by touch and buttons. That made "does this
firmware implement the whole feature?" a question no pointer could answer.
Each namespace now belongs to exactly one feature or to core, so a feature is
a provider pointer and the compiler validates completeness:
gui, node -> screen, tree, under the screen feature
settings -> screen (rotation, theme), sys (timezone),
touch (calibration)
input -> touch, buttons
Runtime::open() no longer requires a GuiProvider; a firmware without one runs
with no screen/tree globals and reports sys.hasFeature("screen") false.
Rotation is one value again: GuiProvider::setRotation applies and persists, so
an app rotating the panel transiently puts the old value back itself.
Fullscreen was the firmware surrendering a strip it clipped apps out of.
The strip is a sibling node now, so an app that wants the panel is chrome
choosing not to build itself.
The controller and the WiFi driver each need a large aggregate allocation,
which a live app sitting on garbage can deny - that is why a failed connect
often succeeded on retry. Both bindings now collect before initializing, and
the tree reserves its node and spec capacity so a build does not reallocate
into a tight heap.