feat(registry): auto-inject Breaks: on Homarr stack for routed visible apps#203
Conversation
…e apps
CPT v0.5.8 made routed apps emit path-only Homarr card URLs
(`url = "/{app_id}/"`). The path-only TOML form requires
`homarr-container-adapter >= 0.4.6` (to accept path-only URLs in
`validate_app_url`) and `halos-core-containers >= 0.3.2` (whose
bundled Homarr fork image accepts path-only `appHrefSchema`).
Without protection, a user who installs a routed container app onto
an older system (Cockpit App Store install, raw `apt install`, or
any partial upgrade) gets the new path-only TOML on a system that
can't process it. The card silently does not appear.
Auto-inject Debian `Breaks: foo (<< X)` clauses for routed visible
apps. `Breaks` is conditional — only enforced when the named peer
is installed. apt either auto-upgrades the peer to satisfy or
refuses the install with a clear error. Does not force the peer to
be installed on systems that don't run Homarr.
Trigger condition mirrors `registry.generate_registry_toml`'s
routed-branch precondition (`routing is not None and
web_ui.enabled and web_ui.visible`) so producer and consumer stay
in lock-step.
App authors may declare additional `breaks:` entries in
`metadata.yaml`; they compose with (do not replace) the
auto-injected entries.
See docs/plans/2026-05-13-001-feat-container-app-breaks-homarr-stack-plan.md
for the design rationale, including why `Breaks` over `Depends`,
why generator-injected over per-app metadata, and how this case
flipped the workspace policy from drop-the-pin to keep-the-pin.
Tests: 15 new (model acceptance + injection trigger matrix + template
rendering). Full suite passes (577 unit + 27 integration).
Future contributors maintaining the generator should know: - which condition triggers auto-injection, - where the version constants live, and - when to bump them.
CE Review — Code-review pass8 reviewer personas spawned in parallel: Verdict: Ready with one substantive change + a small handful of polish items. One issue surfaced by multiple reviewers independently ( P1 — Predicate drift between
|
CE review (PR #203) flagged a predicate drift between the path-only-URL emission in registry.generate_registry_toml and the Breaks-injection trigger in template_context._compute_homarr_stack_breaks. The original injection trigger required `routing AND web_ui.enabled AND web_ui.visible`, but the path-only URL is actually emitted whenever `routing AND web_ui.enabled` — visible is written *into* the TOML, it doesn't gate emission. Concrete consequence before this fix: a routed, enabled, non-visible web app ships a path-only TOML with no Breaks: line. On an older homarr-container-adapter the TOML entry silently fails to load, breaking ping coverage for that app. Fix: extract a single shared predicate `registry.emits_path_only_url` consumed by both call sites. The two cannot drift, and the trigger correctly fires for all path-only emissions (including non-visible routed apps). The original test asserting visible=false suppresses breaks is flipped to assert it injects breaks (since the path-only TOML is still emitted). Also adds an explicit test for the `routing: {}` case to lock in the `is None` semantics against future schema defaults. AGENTS.md updated to describe the correct trigger and to surface app-authored `breaks:` as a peer of `depends`/`conflicts`. Plan doc fixed to attribute the cross-format-identity learning to its actual repo (homarr-container-adapter) rather than the workspace.
|
Pushed What changed
Test impact
Polish also addressed
Polish deferredThese optional P3 items from the review are left for a follow-up if/when the constants need a bump:
Local checks578 unit + 27 integration pass; lint, format, and typecheck unchanged (same 2 pre-existing diagnostics). |
Implements docs/plans/2026-05-13-001-feat-container-app-breaks-homarr-stack-plan.md. Closes the silent-missing-card failure mode after the path-only TOML migration.
Why
CPT v0.5.8 (#202) made routed apps emit path-only Homarr card URLs (
url = "/{app_id}/"). The path-only TOML requires:homarr-container-adapter (>= 0.4.6)—validate_app_urlaccepts path-only.halos-core-containers (>= 0.3.2)— bundled Homarr fork image accepts path-onlyappHrefSchema.Without protection, a user who installs a routed app individually (Cockpit App Store, raw
apt install, any partial upgrade) onto an older system gets the new path-only TOML on a peer that can't process it. The card silently does not appear. No error, no upgrade prompt.Workspace policy
2026-04-30-skip-apt-depends-pins-sibling-halos-packages.mdexplicitly names "manual partial upgrades are an expected operational pattern" as a Keep-the-pin condition.What
Breaks:(notDepends:) is the right primitive: conditional on the peer being installed. A HaLOS device running Signal K without Homarr is unaffected; a device with too-old Homarr gets a cleanapterror or auto-upgrade resolution.Generator-injected (not per-app metadata) because the trigger condition is identical to the trigger for path-only TOML emission (
routing is not None and web_ui.enabled and web_ui.visible). Single source of truth; future minimum-version bumps are one diff intemplate_context.py.Changes
src/schemas/metadata.pybreaks: list[str] | Nonefield onAppMetadata.src/generate_container_packages/template_context.pyHOMARR_ADAPTER_MIN_VERSION = "0.4.6",HALOS_CORE_CONTAINERS_MIN_VERSION = "0.3.2") +_compute_homarr_stack_breakshelper + injection in_build_package_context. App-declaredbreakscompose with (don't replace) auto-injected entries.src/generate_container_packages/templates/debian/control.j2Breaks:block, mirroring the existingConflicts:shape.AGENTS.mdtests/test_models.pytests/test_template_context.pytests/test_renderer.pydocs/plans/2026-05-13-001-...Breaks-vs-Dependsrationale and the cohort-vs-partial-upgrade distinction.Tests
dpkg-buildpackage not availableon macOS dev machines.breaks: list[str]and rejects scalars; injection fires on routed+enabled+visible and does not fire when any of the three is missing; app-declaredbreakscompose after auto-injected entries; explicitNonedoesn't error; rendered control file contains the expectedBreaks:line for routed-visible apps and contains noBreaks:line otherwise.converters/casaos/transformer.pyandrouting.pythat exist on main — not introduced by this PR.)Why minor (0.6.0), not patch (0.5.9)
New user-facing schema field (
breaks) + new observable behavior (auto-injected Breaks lines in every routed visible app's .deb). Backward-compatible feature, which is the textbook minor bump.After merge
halos-org/halos.