sandbox/docs: add core-HA touch-surface slide; note unregister hook

Add PRESENTATION.md Slide 11 enumerating the five core-HA seams (from
ARCHITECTURE.md §12) and the no-monkey-patching discipline. Update §12 +
the slide to include the inverse `async_unregister_remote_platform` hook
that the crash-recovery plan added alongside `async_register_remote_platform`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paulus Schoutsen
2026-07-07 15:13:16 -04:00
co-authored by Claude Opus 4.8
parent 0b10031448
commit bccb217aa5
2 changed files with 26 additions and 1 deletions
+1 -1
View File
@@ -405,7 +405,7 @@ The sandbox is deliberately small against core HA — five surfaces, each a
declared public hook rather than a reach into private internals:
- `config_entries.py` — the `router` attribute + `ConfigEntryRouter` Protocol (three call sites) and the first-class `ConfigEntry.sandbox` field.
- `helpers/entity_component.py``EntityComponent.async_register_remote_platform`, so a sandbox-built `EntityPlatform` attaches without re-discovering the local integration.
- `helpers/entity_component.py``EntityComponent.async_register_remote_platform` (+ its inverse `async_unregister_remote_platform`), so a sandbox-built `EntityPlatform` attaches without re-discovering the local integration, and detaches cleanly on unload/respawn.
- `helpers/sandbox_context.py` (new) + `helpers/storage.py` — the `current_sandbox` ContextVar + `SandboxBridge` Protocol read by `Store`'s IO methods.
- `helpers/translation.py``async_register_sandbox_translation_provider` + the `_TranslationCache` overlay and `async_invalidate_translations` (§11).
- `loader.py``async_register_sandbox_catalog_provider` + the catalog merge in `async_get_integration_descriptions` (§11).
+25
View File
@@ -195,3 +195,28 @@ anywhere a channel can reach — a container today, another machine later.
> Closing beat: nothing here required inventing a new model — the
> sandbox is HA's existing contracts (state machine, service registry,
> event bus, config entries, storage) made remote, one seam at a time.
---
## Slide 11 — What it costs core HA
Almost all of this lives in the `sandbox` component and a separate client
library. The footprint on **core HA itself** is just five seams — each a
*declared public hook*, never a reach into private internals:
| Core file | The hook it adds |
|---|---|
| `config_entries.py` | `router` attribute + `ConfigEntryRouter` Protocol (3 call sites) + the first-class `ConfigEntry.sandbox` field |
| `helpers/entity_component.py` | `async_register_remote_platform` (+ inverse `async_unregister_remote_platform`) — attach/detach a sandbox-built `EntityPlatform` without re-discovering the local integration |
| `helpers/sandbox_context.py` *(new)* + `helpers/storage.py` | the `current_sandbox` ContextVar + `SandboxBridge` Protocol that `Store`'s IO reads |
| `helpers/translation.py` | `async_register_sandbox_translation_provider` + the cache overlay + `async_invalidate_translations` |
| `loader.py` | `async_register_sandbox_catalog_provider` + the catalog merge for the integration picker |
**Five hooks. No monkey-patching. Everything else is the component.**
> This was the design discipline that kept the whole thing reviewable:
> every core touch is a *public seam* other code could legitimately use,
> not a private attribute poked from outside. The one place that started
> as a monkey-patch — rebinding `Store` — was the cautionary tale, and it
> got replaced by the declared `current_sandbox` hook. A reviewer can read
> these five and reason about the entire blast radius on core.