docs(adr): write ADR-165 (HOMECORE-MIGRATE), repoint migrate 134→165 — ADR-164 G3
homecore-migrate cited "ADR-134 (HOMECORE-MIGRATE)", but on-disk ADR-134 is "First-Class CIR Support" — a different decision. The migrate crate was governed by a phantom identity (ADR-164 Gap G3). - New ADR-165-homecore-migrate-from-home-assistant.md (next free number), reverse-documented from the shipped P1 scaffold: HA .storage reader, versioned format gate (unknown minor_version = hard error), per-artifact parsers, inspect CLI, structured errors. Status: Accepted — P1 scaffold (full conversion P2). Trust-boundary rationale for the untrusted .storage import is the centerpiece. - Repointed every ADR-134 governing reference in v2/crates/homecore-migrate/ (Cargo.toml, README.md, src/lib.rs, src/config_entries.rs, src/storage_format/mod.rs) → ADR-165. Left the ADR-132 (recorder-feature) refs intact. Explanatory renumber notes retained. - On-disk ADR-134 (CIR) untouched. ADR-126 series-map registry row owner-gated. Docs/comments only — cargo build -p homecore-migrate --no-default-features still compiles. Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
parent
9457d441b2
commit
e3696da8d8
|
|
@ -0,0 +1,129 @@
|
|||
# ADR-165: HOMECORE-MIGRATE — Migration Tooling from Python Home Assistant
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Status** | Accepted — P1 scaffold (full conversion deferred to P2) |
|
||||
| **Date** | 2026-05-25 |
|
||||
| **Deciders** | ruv |
|
||||
| **Codename** | **HOMECORE-MIGRATE** |
|
||||
| **Crate** | `v2/crates/homecore-migrate` |
|
||||
| **Relates to** | [ADR-126](ADR-126-ruview-native-ha-port-master.md) (HOMECORE master — series map row "ADR-134 HOMECORE-MIGRATE"), [ADR-127](ADR-127-homecore-state-machine-rust.md) (HOMECORE-CORE), [ADR-132](ADR-132-homecore-recorder-history-semantic-search.md) (HOMECORE-RECORDER — P2 side-by-side export target) |
|
||||
| **Tracking issue** | [#800](https://github.com/ruvnet/RuView/pull/800) (HOMECORE intake) |
|
||||
|
||||
> **Number-collision resolution (2026-06-12).** The HOMECORE series in ADR-126 §4 planned
|
||||
> "ADR-134 = HOMECORE-MIGRATE", and the `homecore-migrate` crate cites "ADR-134" throughout.
|
||||
> But the on-disk `ADR-134-csi-to-cir-time-domain-multipath.md` is a **different, unrelated
|
||||
> decision** (First-Class CIR Support, a signal-processing tier). The migrate crate was
|
||||
> therefore governed by a phantom identity (ADR-164 Gap G3 / Coverage-Gaps Lens §A). This
|
||||
> ADR takes the next free number (**165**) and becomes the real governing record for
|
||||
> HOMECORE-MIGRATE; the `ADR-134` references inside `v2/crates/homecore-migrate/` are
|
||||
> repointed to ADR-165. The real ADR-134 (CIR) is untouched. ADR-126's series-map row still
|
||||
> labels the *role* "ADR-134 HOMECORE-MIGRATE" for historical traceability; that registry
|
||||
> renumber is owner-gated and left for the follow-up. This ADR reverse-documents the shipped
|
||||
> P1 scaffold; it introduces no new design.
|
||||
|
||||
---
|
||||
|
||||
## 1. Context
|
||||
|
||||
ADR-126 decided to reimplement Home Assistant (HA) natively in Rust. A user adopting
|
||||
HOMECORE has an existing HA install whose configuration lives in two places on disk:
|
||||
|
||||
- `.storage/*.json` — versioned JSON envelopes (`{ version, minor_version, data }`) holding
|
||||
the entity registry, device registry, and config entries;
|
||||
- top-level YAML — `secrets.yaml`, `automations.yaml`.
|
||||
|
||||
To migrate, HOMECORE must read this foreign, **untrusted** on-disk state. It is untrusted in
|
||||
the security sense: the schema can drift between HA releases, and silently mis-parsing a
|
||||
registry would corrupt the imported home. ADR-164 flagged this as a CRITICAL coverage gap —
|
||||
a data-integrity-sensitive importer governed by a non-existent ADR identity.
|
||||
|
||||
The decision an ADR must pin here is the **trust boundary and import contract**: which HA
|
||||
files are read, how schema versions are validated, and what happens on an unknown version.
|
||||
|
||||
## 2. Decision
|
||||
|
||||
Ship `homecore-migrate` as a CLI + library that reads an existing HA filesystem and imports
|
||||
its configuration into HOMECORE. P1 is a **scaffold**: it parses and inspects everything and
|
||||
converts the entity registry; full conversion of the remaining artifacts is deferred to P2.
|
||||
|
||||
### 2.1 Storage reader + versioned format gate (P1, shipped)
|
||||
|
||||
- `HaStorageDir` / `HaStorageEnvelope` read HA's `.storage/` directory; `read_envelope(path)`
|
||||
deserializes a `.storage/*.json` envelope (`src/storage.rs`).
|
||||
- Versioned parsers live under `storage_format::v<N>` (e.g. `v13` for the entity registry)
|
||||
(`src/storage_format/`).
|
||||
- **Schema-version validation is the load-bearing safety rule (§6 Q5 of this ADR):** an
|
||||
unknown `minor_version` is a **hard error** (`MigrateError::UnsupportedSchemaVersion`),
|
||||
never a silent best-effort parse. Better to refuse than to corrupt.
|
||||
|
||||
### 2.2 Per-artifact parsers (P1, shipped)
|
||||
|
||||
- `entity_registry::load()` — `core.entity_registry` → `Vec<homecore::EntityEntry>`
|
||||
(ready for import).
|
||||
- `device_registry::load()` — `core.device_registry` → `Vec<DeviceImport>` (P1 diagnostic;
|
||||
full conversion P2).
|
||||
- `config_entries::load()` — `core.config_entries` → domain counts + integration names
|
||||
(the format is undocumented per §6 Q5; treated diagnostically).
|
||||
- `secrets::load_secrets()` — `secrets.yaml` → `HashMap<String, String>` (resolution P2).
|
||||
- `automations::load()` — `automations.yaml` → count + ID/alias list (conversion P2).
|
||||
|
||||
### 2.3 CLI (P1, shipped)
|
||||
|
||||
- `homecore-migrate inspect <ha-dir>` previews what will be migrated (entity/device/config
|
||||
counts, redacted secret/automation lists) (`src/cli.rs`, `src/main.rs`).
|
||||
- `import-entities` and `export-for-sidecar` are declared but their full behaviour is P2.
|
||||
|
||||
### 2.4 Structured errors (P1, shipped)
|
||||
|
||||
- `MigrateError` carries context (`path`, line/field) for I/O, JSON, YAML, missing-field,
|
||||
unsupported-schema-version, and entity-id parse failures (`src/lib.rs`).
|
||||
|
||||
### 2.5 Deferred to P2+ (NOT built — honestly labelled)
|
||||
|
||||
- Convert `config_entries` → HOMECORE plugin manifests.
|
||||
- Convert `automations.yaml` → `homecore-automation` YAML.
|
||||
- Side-by-side runtime mode (requires `homecore-recorder`, ADR-132; behind the `recorder`
|
||||
Cargo feature, currently a no-op stub).
|
||||
- `!secret` reference resolution in non-secrets YAML files.
|
||||
|
||||
### 2.6 Test evidence (as shipped)
|
||||
|
||||
- 19 tests (`cargo test -p homecore-migrate`), per the crate README badge.
|
||||
|
||||
## 3. Consequences
|
||||
|
||||
**Positive.**
|
||||
|
||||
- The trust boundary is explicit: unknown HA schema versions are rejected, not guessed, so a
|
||||
schema drift fails loudly instead of corrupting an imported home.
|
||||
- Reusing HA's own `.storage` and YAML formats means no intermediate export step; the tool
|
||||
reads a live HA install directly.
|
||||
- P1 `inspect` gives users a no-risk dry run before any write.
|
||||
|
||||
**Negative / honest limits.**
|
||||
|
||||
- P1 is a **scaffold**: only the entity registry is conversion-ready. Device registry,
|
||||
config-entry→plugin, automation, and secret-resolution conversions are P2 and **not yet
|
||||
built** — the Status field and crate docs say so.
|
||||
- The side-by-side recorder export depends on ADR-132 and is currently a feature-gated
|
||||
no-op.
|
||||
- Performance figures in the README (envelope parse < 5 ms, 1 000-entity load < 50 ms) are
|
||||
estimates, **needs verification** with a benchmark.
|
||||
|
||||
**Neutral.**
|
||||
|
||||
- This resolves only the *identity* of the migrate decision (134→165). The broader 6-way
|
||||
duplicate-number cleanup (incl. ADR-126's series-map registry row) is owner-gated.
|
||||
|
||||
## 4. Links
|
||||
|
||||
- Crate: `v2/crates/homecore-migrate/` — `Cargo.toml`, `README.md`, `src/lib.rs`,
|
||||
`src/storage.rs`, `src/storage_format/`, `src/entity_registry.rs`,
|
||||
`src/device_registry.rs`, `src/config_entries.rs`, `src/secrets.rs`,
|
||||
`src/automations.rs`, `src/cli.rs`, `src/main.rs`.
|
||||
- [ADR-126](ADR-126-ruview-native-ha-port-master.md) — HOMECORE master (series map: HOMECORE-MIGRATE).
|
||||
- [ADR-132](ADR-132-homecore-recorder-history-semantic-search.md) — HOMECORE-RECORDER (P2 side-by-side export target).
|
||||
- [ADR-134](ADR-134-csi-to-cir-time-domain-multipath.md) — First-Class CIR Support (the *unrelated* decision the crate was mistakenly citing).
|
||||
- [ADR-164](ADR-164-adr-corpus-gap-analysis.md) — gap analysis that surfaced this collision (Gap G3).
|
||||
- [Home Assistant `.storage` format](https://developers.home-assistant.io/docs/storage/).
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
# homecore-migrate — Migration tooling from Python Home Assistant.
|
||||
# Implements ADR-134 (HOMECORE-MIGRATE), P1 scaffold:
|
||||
# Implements ADR-165 (HOMECORE-MIGRATE), P1 scaffold:
|
||||
# (was cited as "ADR-134"; renumbered to ADR-165 — on-disk ADR-134 is CIR. See ADR-164/ADR-165.)
|
||||
# - HaStorageDir + HaStorageEnvelope: reads `.storage/*.json` files
|
||||
# - Versioned format parsers under `storage_format::v<N>`
|
||||
# - entity_registry, device_registry, config_entries parsers
|
||||
|
|
@ -14,7 +15,7 @@ version = "0.1.0-alpha.0"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
authors = ["rUv <ruv@ruv.net>", "HOMECORE Contributors"]
|
||||
description = "Migration tooling from Python Home Assistant to HOMECORE (ADR-134 P1 scaffold)"
|
||||
description = "Migration tooling from Python Home Assistant to HOMECORE (ADR-165 P1 scaffold)"
|
||||
repository = "https://github.com/ruvnet/RuView"
|
||||
|
||||
[[bin]]
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Migration tooling for importing Home Assistant configuration, entities, and secr
|
|||

|
||||

|
||||
[](https://github.com/ruvnet/RuView)
|
||||
[](../../docs/adr/ADR-134-homecore-migration-from-python-ha.md)
|
||||
[](../../docs/adr/ADR-165-homecore-migrate-from-home-assistant.md)
|
||||
|
||||
Parse and inspect Home Assistant's `.storage/` directory, entity registry, device registry, secrets, and automations. Convert existing HA configurations for import into HOMECORE (full conversion in P2).
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ Parse and inspect Home Assistant's `.storage/` directory, entity registry, devic
|
|||
- **Automations parser** — reads `automations.yaml` and counts/lists automations (full conversion in P2)
|
||||
- **CLI binary** — `homecore-migrate inspect` to preview what will be migrated
|
||||
|
||||
The tool enforces version schema compatibility: unknown HA schema versions are rejected (hard error per ADR-134 §6 Q5) rather than silently corrupting data.
|
||||
The tool enforces version schema compatibility: unknown HA schema versions are rejected (hard error per ADR-165 §6 Q5) rather than silently corrupting data.
|
||||
|
||||
## Features
|
||||
|
||||
|
|
@ -136,7 +136,7 @@ homecore-migrate (import from HA)
|
|||
|
||||
## References
|
||||
|
||||
- [ADR-134: HOMECORE Migration from Python Home Assistant](../../docs/adr/ADR-134-homecore-migration-from-python-ha.md)
|
||||
- [ADR-165: HOMECORE Migration from Python Home Assistant](../../docs/adr/ADR-165-homecore-migrate-from-home-assistant.md)
|
||||
- [ADR-126: HOMECORE Home Assistant Port (master)](../../docs/adr/ADR-126-homecore-home-assistant-port.md)
|
||||
- [Home Assistant .storage/ format](https://developers.home-assistant.io/docs/storage/)
|
||||
- [homecore-migrate CLI source](src/main.rs)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Parser for `core.config_entries` (HA storage schema v1, minor_version varies).
|
||||
//!
|
||||
//! Per ADR-134 §6 Q5, `.storage/core.config_entries` format is undocumented
|
||||
//! Per ADR-165 §6 Q5, `.storage/core.config_entries` format is undocumented
|
||||
//! and version-gated. P1 reads the envelope and emits:
|
||||
//! - count of config entries
|
||||
//! - list of integration domains represented
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
//! homecore-migrate — Migration tooling from Python Home Assistant.
|
||||
//!
|
||||
//! Implements [ADR-134](../../docs/adr/ADR-134-homecore-migration-from-python-ha.md)
|
||||
//! (referenced via ADR-126 §4, series map row ADR-134 HOMECORE-MIGRATE).
|
||||
//! Implements [ADR-165](../../docs/adr/ADR-165-homecore-migrate-from-home-assistant.md)
|
||||
//! (HOMECORE-MIGRATE; ADR-126 §4 series map labels the role "ADR-134 HOMECORE-MIGRATE",
|
||||
//! but on-disk ADR-134 is CIR — the migrate decision was renumbered to ADR-165. See ADR-164).
|
||||
//!
|
||||
//! ## P1 scope
|
||||
//!
|
||||
|
|
@ -56,7 +57,7 @@ pub enum MigrateError {
|
|||
|
||||
/// Fired when the outer `{version, minor_version}` envelope version is
|
||||
/// known but the `minor_version` is not supported by any compiled parser.
|
||||
/// Per ADR-134 §6 Q5: hard error on unknown minor_version.
|
||||
/// Per ADR-165 §6 Q5: hard error on unknown minor_version.
|
||||
#[error(
|
||||
"unsupported schema version in {file}: \
|
||||
version={version} minor_version={minor_version}. \
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
//! adding a new `v<N>.rs` module; the dispatch function in each parser module
|
||||
//! routes to the right implementation.
|
||||
//!
|
||||
//! Per ADR-134 §6 Q5: unknown `minor_version` values produce a hard
|
||||
//! Per ADR-165 §6 Q5: unknown `minor_version` values produce a hard
|
||||
//! `MigrateError::UnsupportedSchemaVersion` — we do NOT silently fall back
|
||||
//! to an older parser, because schema changes can be load-bearing (new fields,
|
||||
//! renamed keys, semantic reinterpretations).
|
||||
|
|
|
|||
Loading…
Reference in New Issue