From 2116600e246d8ae950bc83181a1c91e9277a352d Mon Sep 17 00:00:00 2001 From: archipelago Date: Wed, 22 Jul 2026 04:54:20 -0400 Subject: [PATCH] fix(pine): write HA bookkeeping fields in seeded config entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HA's config-entries store already carries the current schema minor_version, so entries we append are never migrated — a missing created_at is an unguarded KeyError in config_entries.async_initialize that crash-loops HA at boot (hit on framework-pt during install verify). Write created_at/ modified_at/discovery_keys/subentries on both the anthropic and wyoming entries. Co-Authored-By: Claude Fable 5 --- .../src/api/rpc/package/pine_ha.rs | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/core/archipelago/src/api/rpc/package/pine_ha.rs b/core/archipelago/src/api/rpc/package/pine_ha.rs index 0d2f4daf..e5a7b939 100644 --- a/core/archipelago/src/api/rpc/package/pine_ha.rs +++ b/core/archipelago/src/api/rpc/package/pine_ha.rs @@ -24,6 +24,13 @@ use serde_json::{json, Value}; use tracing::{info, warn}; +/// Timestamp in the exact format HA writes to `.storage` +/// (`2026-07-22T08:29:35.123456+00:00` — micros, `+00:00` offset), safe for +/// Python's `datetime.fromisoformat`. +fn ha_now() -> String { + chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Micros, false) +} + const HA_CONFIG_DIR: &str = "/var/lib/archipelago/home-assistant"; const HA_STORAGE_DIR: &str = "/var/lib/archipelago/home-assistant/.storage"; const NODE_SECRETS_DIR: &str = "/var/lib/archipelago/secrets"; @@ -444,8 +451,11 @@ async fn seed_claude_conversation(storage: &std::path::Path) -> ClaudeSeed { let id = |raw: [u8; 16]| hex::encode(raw); // Shape mirrors what HA 2026.7's anthropic config flow creates (entry - // version 2.4 with conversation + ai_task subentries); HA fills any - // missing bookkeeping fields on load. + // version 2.4 with conversation + ai_task subentries). Bookkeeping + // fields (created_at/modified_at/discovery_keys) must be written here: + // the store already carries HA's current schema minor_version, so HA + // never migrates appended entries — a missing created_at is a + // KeyError that crash-loops HA at boot. entries.push(json!({ "entry_id": id(rand::random()), "version": 2, @@ -459,6 +469,9 @@ async fn seed_claude_conversation(storage: &std::path::Path) -> ClaudeSeed { "source": "user", "unique_id": null, "disabled_by": null, + "created_at": ha_now(), + "modified_at": ha_now(), + "discovery_keys": {}, "subentries": [ { "subentry_id": id(rand::random()), @@ -555,7 +568,11 @@ async fn seed_wyoming_config_entries(storage: &std::path::Path) -> bool { "pref_disable_polling": false, "source": "user", "unique_id": null, - "disabled_by": null + "disabled_by": null, + "created_at": ha_now(), + "modified_at": ha_now(), + "discovery_keys": {}, + "subentries": [] })); info!("pine/HA seed: added wyoming config entry {title} ({host}:{port})"); added = true;