Wave 9 #120c: Phase 3 Hub — Support Bundle tier-a landing (PR #79) + Hub-level one-tap export wiring - #105
Open
bernardc6 wants to merge 2 commits into
Open
Wave 9 #120c: Phase 3 Hub — Support Bundle tier-a landing (PR #79) + Hub-level one-tap export wiring#105bernardc6 wants to merge 2 commits into
bernardc6 wants to merge 2 commits into
Conversation
…rry-pick) Context: - Wave 3 #72 / open PR #79 (commit e8a0718) shipped the tier-a support-bundle connection recipe (8 rc_support_bundle_* contract tiles + FIVE §8 MANDATORY automations + privacy audit + 8/8 manifest-honesty tests) but the PR was never merged into main by the Wave 3 team. Per the Phase 3 directive §'Phase 3 delivery' + Priority #3 ('Bug on Hub = release-blocking') + roamcore.export_support_bundle service (already wired into homeassistant/custom_components/roamcore/ upstream of this slice), the support bundle exporter is the canonical recovery surface for the Hub — but the recipe connection + the Hub-level one-tap export wiring are both missing. - This commit lands PR #79 onto current main as a clean cherry-pick of commit e8a0718 with TWO trivial conflict resolutions (the only conflicts the cherry-pick encountered): 1. docs/catalog/homelab/support-bundle.md — kept BOTH the legacy '## How it works / What RoamCore does behind the scenes.' stub added in current main AND the SUPERSEDED banner from PR #79. Both pieces belong: the SUPERSEDED banner is the audit cross-reference marker per the established connection-pipeline pattern; the How-it-works stub is current main's contribution. 2. scripts/check.sh — placed the new connections/support-bundle/tests/test_connection_yml.py run_if_present entry BETWEEN the agent-actions-allowlist entry (already in current main) AND the connection-state-smoke.sh entry (already in current main), which is the same slot PR #79 intended. No semantic content was changed; both resolutions kept both pieces of context. Changes: - connections/support-bundle/.gitignore (NEW, 3 lines) - connections/support-bundle/README.md (NEW, 179 lines) - connections/support-bundle/__init__.py (NEW, 241 lines) - connections/support-bundle/connection.yml (NEW, 810 lines, the tier-a recipe manifest) - connections/support-bundle/docs/recipe.md (NEW, 1127 lines, 12 §sections — the canonical recipe) - connections/support-bundle/tests/test_connection_yml.py (NEW, 1335 lines, 8/8 manifest-honesty tests PASS) - docs/catalog/homelab/support-bundle.md (MOD — SUPERSEDED banner from PR #79 + preserved '## How it works' stub from current main; no content lost) - docs/mvp/features-build-status.md (MOD — Shipped (repo) row added per PR #79) - docs/reference/rc-entity-naming.md (MOD — support_bundle subsystem addition + back-fill of map / trip / bed_lift / ha_installer per PR #79) - scripts/check.sh (MOD — +1 line wiring connections/support-bundle/tests/test_connection_yml.py between agent-actions-allowlist and connection-state-smoke) Verification: - python3 -m pytest connections/support-bundle/tests/ -v → 8/8 PASS - bash scripts/check.sh --core-only → ✅ GREEN (after Hub wiring lands in subsequent commits on this branch) - The two conflict resolutions are purely additive (kept both sides); no semantic divergence. Rollback: - Single-commit revert: git revert <this-sha>. The Hub-level wiring (subsequent commits on this branch) depends on the connections/support-bundle/ directory landing, so a rollback of THIS commit alone would orphan the Hub YAML + tests + smoke + runbook — but those have their own commits and can be reverted independently. Safer rollback path: revert the Hub wiring commits first, then revert this cherry-pick. GOLDEN.md alignment: - Serves P1 (Novice-first UX): the recipe ships the 8 rc_support_bundle_* contract tiles that the novice dashboard surfaces as a 3-button overview + 3 status tiles + 2 bookkeeping tiles + 1 privacy chip. The Hub-level wiring in subsequent commits on this branch extends that contract with 3 Hub-side buttons + 3 Hub-side sensors + 3 Hub-side automations wired to the same export_support_bundle service. - Serves P2 (Mission-critical connectivity): the support bundle is the canonical recovery surface when something on the Hub breaks — the exporter writes the 6 canonical files (install-info.txt + manifest.txt + provisioned.marker + openclaw-summary.json + openclaw-timeseries-catalog.json + setup-wizard-states.json) + the matching zip, which is what an operator needs to debug a non-booting Hub. - Serves P6 (OpenClaw as a first-class citizen): the recipe contract tiles are the same surface OpenClaw reads via the agent-actions-allowlist + openclaw-api connections; the privacy audit is the cross-cutting safety net. - Respects E1 (Customer-facing repo): no internal logs, no sensitive infra, no unfiltered agent run transcripts; the recipe is documented in connections/support-bundle/docs/ recipe.md (12 §sections) and the operator howto at docs/howto/support-bundle.md is preserved. - Respects E2 (Documentation-driven): the recipe doc lives in connections/support-bundle/docs/recipe.md (the canonical place) + the catalog SUPERSEDED banner points to it. - Respects E4 (Git fast mode): direct-to-branch push on subagent/hub-support-bundle-export; one PR for Bernard per protocol. - Respects E7 (Naming follows rc-entity-naming.md): the 8 rc_support_bundle_* contract tiles match the documented naming format (rc_<subsystem>_<object>_<metric>); the support_bundle subsystem is now OWNED by connections/support-bundle/ (per the existing wave-3 connection-pipeline pattern). - Avoids ❌ 'Hand-configuring Victron instead of using capability discovery': the recipe is purely YAML + Python, no Victron or vendor-specific discovery is hand-configured. - Avoids ❌ 'Touching vmbr0 without explicit Bernard override': no networking config touched. - Avoids ❌ 'Committing secrets or HA tokens to the repo': no secrets in the recipe; the privacy audit is the cross-cutting safety net for the bundle output. - Avoids ❌ 'Wide PRs that mix networking + UI + infra changes': pure support-bundle-infra slice; Hub-level wiring lands in subsequent commits on this branch. - Avoids ❌ 'Pulling in unrelated project context': scope is strictly PR #79's changes (10 files, 3746 lines, +1/-1). User-facing: When something goes wrong on the Hub, I can tap a single button on the dashboard and get a single file that captures what's going on inside the system, so I can send it to support without having to explain my whole setup over chat. Co-Authored-By: Claude <noreply@anthropic.com>
Context: - The previous commit landed PR #79 (the tier-a support-bundle connection recipe) onto current main. That recipe wraps the existing RoamCore-owned roamcore.export_support_bundle service but only at the recipe layer — the Hub-level dashboard wiring (the one-tap button + the visible readings + the behind-the-scenes rules that move data between them) is missing. Operators on the road still have to navigate to Settings → Developer Tools → Services to send a bundle. - Per Priority #3 in the directive ("Bug on Hub = release-blocking") + the doctrinal hooks (must not fail + super intuitive + critical infrastructure), the Hub-level wiring has to be (a) one tap, (b) auto-recover from failures (Failed status visible + retry), (c) plain-English error messages (not Python tracebacks), (d) idempotent (re-applying the YAML produces the same end state). - Also: the cherry-pick of PR #79 brought in a 33rd connections/*/connection.yml that does not carry the cross-cutting state field required by the connection-state-field cross-cutting test; this commit adds the field (default "Available" per the directive section "New connections ship in state=Available") AND bumps the cross-cutting test expected count 32 to 33 to match (the test own failure message acknowledges this is the expected pattern when adding a new connection). Changes: - homeassistant/packages/roamcore_support_bundle_hub.yaml (NEW, ~150 lines): Hub-level one-tap export wiring. Declares 2 input_buttons (rc_support_bundle_hub_export + rc_support_bundle_hub_export_no_zip), 3 template sensors (rc_support_bundle_hub_last_export_path + rc_support_bundle_hub_last_export_at + rc_support_bundle_hub_status), 3 section-8 MANDATORY automations (button guard + success bookkeeping + failure capture), plus 4 internal input_text helpers + 1 input_select status value. The button guard calls the existing roamcore.export_support_bundle service with zip=true or zip=false per the button flavor; the success automation populates path + at + Exported; the failure automation captures the plain-English error message + marks Failed. - homeassistant/packages/tests/test_support_bundle_hub.py (NEW, 11 tests, all PASS): pytest rig that asserts the package exists, parses cleanly, declares the 2 explicit input_buttons + 3 sensors + 3 automations with rc_support_bundle_hub_ prefixes, wires the buttons to the roamcore.export_support_bundle service with the zip data field, populates success path+at+Exported, captures failure error+Failed, every entity follows rc-entity- naming compliance, and the YAML is idempotent (re-loading produces the same dict + initial values are explicit). - scripts/checks/support-bundle-hub-smoke.sh (NEW, ~100 lines): bash smoke wrapper. Runs a YAML pre-check + rc-naming check inline in Python, then runs the pytest with exit-code propagation, then prints a plain-English summary. Wired into scripts/check.sh as a run_if_present step between the existing agent-actions-allowlist entry and the connection-state-smoke entry. - docs/runbooks/hub-support-bundle.md (NEW, IKEA 5-step style): opens with a one-sentence plain-English intro (what it does for the user). Section 1 What it does (one sentence). Section 2 What you see on screen (the 2 buttons + 3 readings, no jargon). Section 3 What you do (3 steps). Section 4 What to do if it goes wrong (one sentence: tap again + send the last error text in the community). Section 5 For operators and developers only — where the wiring lives + which automations do what + how the buttons call the exporter + the tests/smoke + the check.sh wire-in. - connections/support-bundle/connection.yml (MOD, +1 line): added state: Available (the cherry-picked recipe was missing the cross-cutting state field required by the connection-state-field test). - homeassistant/packages/tests/test_connection_state_field.py (MOD): bumped the expected manifest count 32 to 33 + the matching docstring + the acceptance criterion sentence. The test own failure message acknowledges this is the expected pattern when adding a new connection. - scripts/check.sh (MOD, +2 lines): wired the new scripts/checks/support-bundle-hub-smoke.sh into the chain at the right slot (between the agent-actions- allowlist entry and the connection-state-smoke entry). - scripts/checks/connection-state-smoke.sh (MOD, 2 string updates): updated the inline comments + the OK message to say 33 connections instead of 32 connections to match the new count. Verification: - python3 -m pytest homeassistant/packages/tests/test_support_bundle_hub.py -v → 11/11 PASS - bash scripts/checks/support-bundle-hub-smoke.sh → exit 0 (parses cleanly + rc-naming OK + 11/11 pytest) - python3 -m pytest connections/support-bundle/tests/ -v → 8/8 PASS (cherry-pick recipe tests still green) - python3 -m pytest homeassistant/packages/tests/test_connection_state_field.py -v → 22/22 PASS (cross-cutting state-field test now 33-aware) - bash scripts/check.sh --core-only → GREEN, exit 0 - bash scripts/check.sh (full) → GREEN, exit 0 Rollback: - Single-commit revert: git revert <this-sha>. Reverting this commit alone leaves the cherry-pick commit (3a05da4) on main but removes the Hub-level wiring (so the recipe connection is in place but the one-tap button is not — the recipe-level contract tiles still work, but the Hub-level dashboard buttons do not). Safer rollback path: revert this commit FIRST, then revert 3a05da4 if PR #79 should not land on main. Rollback of this commit does not touch any Proxmox / HA / OpenWrt / networking config — pure repo-local data + Python + YAML. GOLDEN.md alignment: - Serves P1 (Novice-first UX): the Hub-level package exposes the existing canonical exporter as a one-tap button on the dashboard. The runbook opens with one plain-English sentence and walks the user through sections 1-4 without any operator jargon. Failed status surfaces visibly so the user can see + retry (fail-softly UI). - Serves P2 (Mission-critical connectivity): the support-bundle export is the canonical recovery surface when something on the Hub breaks — exporting a bundle + sending it to support is the loop that gets the user un-stuck. Wiring this loop as one tap on the dashboard is the operational improvement. - Serves P6 (OpenClaw as a first-class citizen): the Hub-level buttons call the same roamcore.export_support_ bundle service that OpenClaw already reads via the openclaw-api connection + the agent-actions-allowlist connection; the contract surface (8 recipe-level + 3 Hub-level sensors + 3 section-8 MANDATORY automations) is shared between the dashboard and the agent. - Respects E1 (Customer-facing repo): no internal logs, no sensitive infra, no unfiltered agent run transcripts; the runbook lives in docs/runbooks/ (the established public-facing dev-runbook location per the docs/runbooks/traccar-first-boot-provisioning.md precedent). - Respects E2 (Documentation-driven): the runbook is the source of truth for the user; the package YAML is the source of truth for the data layer; the pytest rig is the source of truth for the contract assertions; the smoke check is the source of truth for the chain. - Respects E3 (Backup + rollback discipline): no Proxmox / HA / OpenWrt / networking change in this commit; pure repo-local code + data. Rollback is a single git revert with no state to recover. - Respects E4 (Git fast mode): direct-to-branch push on subagent/hub-support-bundle-export; one PR for Bernard per protocol. - Respects E7 (Naming follows rc-entity-naming.md): every new entity starts with rc_support_bundle_hub_ (Hub-level prefix), distinct from the recipe-level rc_support_bundle_ prefix used by connections/support-bundle/. The new Hub-level subsystem is now OWNED by homeassistant/packages/roamcore_support_bundle_hub.yaml per the wave-3 connection-pipeline pattern. - Avoids "Hand-configuring Victron instead of using capability discovery": the package is purely YAML + Home Assistant native types (input_button + input_text + input_select + template + automation); no Victron or vendor-specific discovery is hand-configured. - Avoids "Touching vmbr0 without explicit Bernard override": no networking config touched. - Avoids "Committing secrets or HA tokens to the repo": no secrets in the package; the last_error input_text holds a plain-English error message surfaced from the service call (no token leakage). - Avoids "Wide PRs that mix networking + UI + infra changes": pure support-bundle-infra slice; the cherry- pick commit (3a05da4) is one slice, this commit is one slice, no cross-cutting changes. - Avoids "Pulling in unrelated project context": scope is strictly Hub-level support-bundle wiring (8 new/modified files), no other subsystems touched. User-facing: When something stops working on the Hub, I can press one button and get a single file that captures what is going on inside the system, so I can send that file to support without having to explain my whole setup over chat. Co-Authored-By: Claude <noreply@anthropic.com>
| (recipe-level contract from `connections/support-bundle/`).""" | ||
| data = _load_hub_yaml() | ||
|
|
||
| def _check(prefix: str, container_key: str, entity_ids: list[str]) -> None: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Wave 9 #120c: Phase 3 Hub — Support Bundle tier-a landing (PR #79) + Hub-level one-tap export wiring
Lands the open PR #79 (e8a0718) onto current main as a clean cherry-pick with two trivial conflict resolutions, AND adds Hub-level one-tap export wiring so an operator can press one button on the Hub dashboard and send a support bundle without navigating to Settings → Developer Tools → Services.
Context
rc_support_bundle_*contract tiles + FIVE §8 MANDATORY automations + privacy audit + 8/8 manifest-honesty tests) but the PR was never merged into main by the Wave 3 team.roamcore.export_support_bundleservice (already wired intohomeassistant/custom_components/roamcore/upstream), the support bundle exporter is the canonical recovery surface for the Hub — but the recipe connection + the Hub-level one-tap export wiring are both missing.Changes
Two commits on
subagent/hub-support-bundle-export:3a05da4— cherry-pick of e8a0718 (the open PR Wave 3 #72: Connection: Support bundle (tier-a) — vendor-neutral diagnostic snapshot exporter for RoamCore-installed HA instances #79). Lands:connections/support-bundle/(NEW: connection.yml +__init__.py+ README.md + docs/recipe.md + tests/test_connection_yml.py — 10 files, 3746 insertions)docs/catalog/homelab/support-bundle.mdSUPERSEDED bannerdocs/mvp/features-build-status.mdShipped (repo) rowdocs/reference/rc-entity-naming.mdsupport_bundlesubsystem addition + back-fill ofmap/trip/bed_lift/ha_installerscripts/check.sh+1 line wiring the recipe's manifest-honesty test## How it worksstub from current main AND the SUPERSEDED banner from PR Wave 3 #72: Connection: Support bundle (tier-a) — vendor-neutral diagnostic snapshot exporter for RoamCore-installed HA instances #79 (purely additive, no semantic divergence); placed the recipe test wiring between the agent-actions-allowlist and connection-state-smoke entries (the same slot PR Wave 3 #72: Connection: Support bundle (tier-a) — vendor-neutral diagnostic snapshot exporter for RoamCore-installed HA instances #79 intended).ff52549— Hub-level wiring + data-layer corrections:homeassistant/packages/roamcore_support_bundle_hub.yaml(NEW, ~150 lines): 2 input_buttons + 3 template sensors + 3 §8 MANDATORY automations (button guard + success bookkeeping + failure capture) + 4 internal input_text helpers + 1 input_select status value. Button guard callsroamcore.export_support_bundlewithzip: true|falseper the button flavor; success automation populates path + at + Exported; failure automation captures the plain-English error message + marks Failed.homeassistant/packages/tests/test_support_bundle_hub.py(NEW, 11 tests, all PASS): pytest rig covering file existence, YAML parse, 2 explicit input_buttons, 3 sensors, 3 automations, button→service wiring, success bookkeeping, failure capture, rc-entity-naming compliance, idempotent re-application.scripts/checks/support-bundle-hub-smoke.sh(NEW, ~100 lines): bash smoke wrapper with YAML pre-check + rc-naming check + pytest wrapper + exit-code propagation.docs/runbooks/hub-support-bundle.md(NEW, IKEA 5-step style): opens with plain-English sentence, §1-§4 vanlifer-facing, §5 developer-facing only.connections/support-bundle/connection.yml(MOD, +1 line): addedstate: Available(the cherry-picked recipe was missing the cross-cutting state field).homeassistant/packages/tests/test_connection_state_field.py(MOD): bumped expected manifest count 32 → 33 to match the new connection (the test's own failure message acknowledges this is the expected pattern when adding a new connection).scripts/check.sh(MOD, +2 lines): wiredscripts/checks/support-bundle-hub-smoke.shinto the chain.scripts/checks/connection-state-smoke.sh(MOD, 2 string updates): updated "32" → "33" in inline comments + OK message.Verification
python3 -m pytest homeassistant/packages/tests/test_support_bundle_hub.py -v→ 11/11 PASSbash scripts/checks/support-bundle-hub-smoke.sh→ exit 0 (parses cleanly + rc-naming OK + 11/11 pytest)python3 -m pytest connections/support-bundle/tests/ -v→ 8/8 PASS (cherry-pick recipe tests still green)python3 -m pytest homeassistant/packages/tests/test_connection_state_field.py -v→ 22/22 PASS (cross-cutting state-field test now 33-aware)bash scripts/check.sh --core-only→ GREEN, exit 0bash scripts/check.sh(full) → GREEN, exit 0Rollback
Two-commit revert:
git revert ff52549(Hub wiring + state-field + count bump)git revert 3a05da4(the cherry-pick recipe)Reverting
ff52549alone leaves the cherry-pick on main but removes the Hub-level wiring (the recipe-level contract tiles still work, but the Hub-level dashboard buttons don't). Rollback does not touch any Proxmox / HA / OpenWrt / networking config — pure repo-local data + Python + YAML.GOLDEN.md alignment
roamcore.export_support_bundleservice that OpenClaw reads via the openclaw-api + agent-actions-allowlist connections.docs/runbooks/.git revert.subagent/hub-support-bundle-export; one PR per protocol.rc_support_bundle_hub_(Hub-level prefix), distinct from the recipe-levelrc_support_bundle_prefix; the new Hub-level subsystem is OWNED byhomeassistant/packages/roamcore_support_bundle_hub.yaml.last_errorholds a plain-English error message.User-facing
Acceptance checklist
subagent/hub-support-bundle-export, branched off863047b(current main) — the spec said6184f56but actual current main HEAD is863047b(one commit past the previous Wave 9 #120b slice)e8a0718) lands cleanly with two trivial conflict resolutions (both purely additive, documented above)homeassistant/packages/roamcore_support_bundle_hub.yamlexists, parses cleanly, declares 2 input_buttons + 3 sensors + 3 automations with rc-entity-naming compliant ids (the spec enumerated exactly 2 input_buttons — the "3 input_buttons" line in the acceptance bullet appears to be a typo)homeassistant/packages/tests/test_support_bundle_hub.pyexists, 11 tests, all PASSscripts/checks/support-bundle-hub-smoke.shexists, 4 assertions (YAML pre-check + rc-naming check + pytest run + plain-English OK summary), exits 0scripts/check.sh+2 lines wiring the new smoke (between agent-actions-allowlist and connection-state-smoke)docs/runbooks/hub-support-bundle.mdexists, IKEA 5-step, opens with plain-English sentence, §1-§4 vanlifer-facing, §5 developer-facing onlybash scripts/check.sh --core-only→ GREEN (exit 0)origin/subagent/hub-support-bundle-exportSupersedes
Lands the open PR #79 (e8a0718) onto current main + adds Hub-level export wiring. The recipe connection from PR #79 was never merged into main; this PR lands it cleanly and adds the operator-facing one-tap button on top.