feat(install): route any manifest-known app through the orchestrator

package.install routed to the manifest-driven orchestrator only for a
hardcoded per-app allowlist; every other app fell through to the legacy
flow, which ignores manifests entirely and creates a bare container with
no ports or volumes (strfry crash-looped this way on .228, 2026-07-09).

New ContainerOrchestrator::knows_app(app_id) (default false; prod checks
its loaded-manifest map, disk + signed-catalog overlay). The install gate
is now allowlist OR knows_app — no per-app Rust for manifest-driven apps,
matching the packaging invariant. Apps without a manifest keep the legacy
flow including the container-exists adopt block; the unknown-app_id →
legacy fallback inside the orchestrator branch is unchanged.

Tests: knows_app_reflects_loaded_manifests + install suite 37/37.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-07-09 14:46:50 -04:00
co-authored by Claude Fable 5
parent 707c912606
commit 55c20e0d6e
3 changed files with 49 additions and 2 deletions
@@ -330,8 +330,20 @@ impl RpcHandler {
// mode).
// The adoption block is being phased out as apps move to the
// orchestrator path. Non-orchestrator apps still hit it.
let orchestrator_managed =
should_try_orchestrator_install(package_id, self.orchestrator.is_some());
let orchestrator_managed = match self.orchestrator.as_ref() {
// Migration allowlist OR any app whose manifest the orchestrator
// knows (disk or signed-catalog overlay). A manifest-driven app
// must never fall through to the legacy flow — it ignores the
// manifest entirely and creates a bare container with no ports or
// volumes (strfry, 2026-07-09).
Some(orch) => {
should_try_orchestrator_install(package_id, true)
|| orch
.knows_app(orchestrator_install_app_id(package_id))
.await
}
None => false,
};
// Check if container already exists (legacy adoption — non-orchestrator
// apps only).