DPF resolves physical services from governed runtime capabilities. This keeps install, restart, transition, backup, diagnostics, and health behavior on one authority path instead of maintaining a service list in each consumer. The broader rationale and acceptance gates remain in the platform substrate convergence design; this page is the operating architecture implemented by BI-PSC-003.
Authority flow
flowchart LR
SM["Platform substrate manifest\nphysical service facts"] --> GC["Generated capability-service catalog\nversioned and hashed"]
CM["PlatformCapability.manifest.runtime\ndependencies and activation policy"] --> GC
IS["install-state.json\nenabled keys and hashes"] --> RP["Capability service projection"]
LS["PlatformCapability.state\nlive post-bootstrap state"] --> OS["OperationalCapabilityState"]
GC --> RP
RP --> OS
DO["Docker Engine observation"] --> OS
PH["Provider health reconciliation"] --> OS
RP --> IU["install · restart · upgrade · rollback"]
OS --> BH["backup · diagnostics · health UI"]
The checked-in substrate manifest owns service names, Compose profiles, host support, dependencies, data ownership, backup policy, health semantics, and boundary class. Runtime capability definitions are seeded from platform-runtime-capabilities.json; their manifest.runtime metadata owns capability dependency and activation policy, while live PlatformCapability.state is the post-bootstrap enabled-state authority.
compile-capability-service-catalog.mjs joins those sources into the checked-in generated catalog. Its catalog hash and deterministic capability-state hash bind a persisted install snapshot to the exact catalog and enabled set. resolve-capability-compose-profiles.mjs is the lifecycle adapter; capability-service-projection.ts is the web adapter. Both delegate dependency closure to the same catalog contract. Unknown capabilities, conflicting hashes, duplicate authorities, and stale state fail closed.
After bootstrap, OperationalCapabilityState joins the catalog projection, install-state.json, live database state, bounded Docker Engine observations, and reconciled provider observations. Backup, readiness, the runtime-health page, and system health consume that object rather than reconstructing topology.
Profiles and host filtering
For locally capability-activated services, runtime profile names are mechanically derived from stable capability keys. Separately distributed and development-only boundaries retain their explicit profile contracts instead of being renamed to runtime-*:
| Capability | Canonical Compose profile | Local services |
|---|---|---|
runtime:build |
runtime-build |
sandbox-postgres, sandbox-init, sandbox |
runtime:browser-automation |
runtime-browser-automation |
browser-use |
runtime:durable-automation |
runtime-durable-automation |
redis, redis-exporter, inngest |
runtime:local-speech |
runtime-local-speech |
dpf-tts (speech-to-text is provider-managed, not a local service — see below) |
runtime:deep-observability |
runtime-deep-observability |
Prometheus, Grafana, and PostgreSQL exporter (Loki and Alloy are always-on runtime:core services, BI-F8024A9D). The operator chooses it at install or in Settings → Monitoring (BI-83260BB3). |
runtime:external-ai |
runtime-external-ai on Linux |
Ollama from the Linux overlay; configured external providers remain provider-managed |
runtime:adp-integration |
integrations-adp (separate-distribution exception) |
adp |
runtime:development |
dev and integration-test (lifecycle-only) |
dev-postgres, dev-init, dev-portal, and integration-test-harness |
Speech-to-text is provider-managed, not a local service (BI-F7E9A541). DPF previously shipped a digest-pinned third-party whisper image as dpf-stt under runtime:local-speech. Because the release manifest guard deliberately covers images behind optional profiles, a publisher pruning that digest failed install verification and froze the :latest pointer for every install — three times. Speech-to-text therefore moved to the External — provider managed class described in the health table below: availability follows provider configuration and there is no local container. Configuring any provider that serves an OpenAI-compatible /v1/audio/transcriptions endpoint enables voice input, because endpoint resolution already skips candidates whose provider is not active. An operator who wants audio to stay on their own infrastructure runs their own speech server and supplies its base URL, rather than DPF shipping and pinning one. runtime:local-speech still owns dpf-tts. A tag pin alone was not safe from the same failure: the publisher deleted travisvn/chatterbox-tts-api:v0.1.0, so dpf-tts could not be created on any install. It is now pinned by tag and digest (gpu@sha256:…, the CUDA build of upstream v1.0.1; the CPU build is the documented override), per the evaluation in docs/security/tool-evaluations/2026-10-07-chatterbox-tts-api.md (BI-E2763038). The release guard (scripts/release/verify-compose-image-manifests.mjs --only third-party) checks every third-party image, tag- or digest-pinned, and carries no exception for it (BI-DB87D925). dpf-tts is declared for Linux and Windows only: macOS speaks through the host-native Chatterbox service, so no macOS install requires the container.
How an upgraded install reaches its required services. A fresh install runs a full docker compose up -d; a self-upgrade creates missing services in scripts/promote.sh step 7d (service-reconcile), against requiredServices from the capability projection. Each missing service is created on its own up, so one image that cannot be pulled leaves only that service absent. The new portal marks the run succeeded when it boots, before step 7d runs, so promote.sh writes what it created and what it could not to service-reconcile-outcome.json on the state mount. The portal merges that into the run’s completionEvidence.serviceReconcile, and the Upgrade Center shows the run as degraded and names the services that are not running. The run’s status stays succeeded, because the portal swap did land and the upstream freshness gate reads the latest succeeded run (BI-DB87D925).
Service inventory matching uses exact names and direct input redirection. An early-exiting search in a pipeline can make its writer fail under pipefail, falsely classifying an existing service as missing. Inventory size must not change the recovery decision: only missing services and containers proven never started are candidates for creation; intentionally stopped services remain stopped.
PostgreSQL, portal-init, and the portal are runtime:core and have no profile. The resolver filters service bindings by hostPlatforms before returning profiles and required services. The promoter and the portal’s operational projection take the host from the same place, install-state.json platform; the portal had passed no host and so reported host-scoped services such as dpf-tts as degraded on macOS (BI-E2763038). The Linux overlay therefore provides a deliberate hybrid: the same runtime:external-ai capability can select host-local Ollama on Linux while external provider configurations remain outside Compose on every host. Linux-only cadvisor and node-exporter remain under the explicit linux-monitoring overlay.
Lifecycle overlays are not capability state. promote, dev, integration-test, linux-monitoring, and linux-host-network are explicit, allowlisted overlays. runtime:development has activationPolicy: lifecycle-profile; selecting dev or integration-test is therefore explicit lifecycle intent and does not convert development infrastructure into an install capability profile. The runtime:adp-integration binding is also intentionally exceptional: its adp service remains a separate-distribution boundary under the retained integrations-adp profile, rather than being folded into the local runtime-profile naming convention. The one-release compatibility aliases are:
tts→runtime:local-speech→runtime-local-speechobservability-ui→runtime:deep-observability→runtime-deep-observability
The governed Compose wrapper locates the install from the canonical project root and Compose file chain, loads that install’s state, resolves host-aware profiles, and replaces caller-supplied capability profiles with the canonical set. Direct attempts to enable a disabled runtime-* profile or an unapproved profile fail. Explicit lifecycle overlays survive this normalization. Installer, setup, start, autostart, and promotion paths call the same adapter.
Capability transitions
Enabling resolves the full dependency closure, persists the desired catalog/state identity, starts the required services, and commits live capability state only after the signed host receipt proves the exact topology and required health. Disabling first closes work admission. If a declared work guard has queued or running work, the request returns drain_required with blocker counts and leaves the current projection active. Once drained, the transition stops and removes services no longer required.
The transition protocol uses an HMAC-signed, expiring envelope containing the transition identifier, prior and desired keys, hashes, profiles, and services. The promoter has the only read-write /dpf-state mount. The host apply script serializes transitions, writes the install snapshot atomically, reconciles explicit service deltas, observes the Compose project, and writes a signed receipt. Its journal permits a crash-safe retry. A failed reconcile or required-health check restores the previous install snapshot and service closure; an unverifiable rollback is reported as rollback_failed, never as success. Startup reconciliation completes or compensates pending database receipts before admitting another transition.
Host apply can recreate the portal before it writes its receipt. A process-owned observer checks for late signed receipts every 30 seconds, independently of optional job infrastructure. This observer never launches or compensates host work when a receipt is absent. Startup and live completion share the transactional envelope, database-baseline and audit fences; identical completion is idempotent. Serialization contention leaves the existing transition available for the next pass. Admission still checks durable active and recovery-required rows, and background observation cannot reopen a failed startup barrier.
Health is an observation of the desired state, not permission to enable or disable a capability.
Retiring a capability
Retirement is declared, and it is two-phase. A capability carries two independent axes: state
(active | disabled) is enablement — whether this install has it turned on, tracked per-install in
the database — and lifecycle (absent, meaning active, or retired) is lifecycle — whether the
platform still offers it at all. Conflating them would make “the operator turned it off”
indistinguishable from “the platform withdrew it”, so a retired capability may not also be state:
active; the compiler refuses that contradiction.
To retire a capability:
- Mark it
lifecycle: "retired"andstate: "disabled"in the capability seed, and leave the entry in the catalog for at least one release. Installs migrate off it on their next upgrade: the projection drops it fromenabledRuntimeCapabilities, restamps the snapshot, and reports it indroppedRetiredCapabilitiesso the withdrawal is visible rather than silent. - Only then delete the entry, once every supported install has upgraded past step 1.
Deleting the entry without step 1 wedges every install that still has the capability enabled. Nothing vouches for an id that is simply absent, so it cannot be told apart from a corrupt or hand-edited snapshot — the projection fails closed, and the upgrade that would have dropped the capability is the upgrade it blocks (BI-5AA0345E). That is the same self-wedging shape as a moved catalog hash (install-state readiness migration §7) and an N-1 promoter build context.
A retired capability that is still a dependency of a live one is a catalog authoring error, reported as
retired_runtime_capability_required, not silently projected.
Install, upgrade, consumer assets, and rollback
The persistent snapshot stores sorted enabledRuntimeCapabilities, capabilityCatalogHash, and capabilityStateVersion. POSIX hosts use $XDG_STATE_HOME/dpf/install-state.json when XDG_STATE_HOME is set and otherwise $HOME/.dpf/install-state.json; Windows uses %USERPROFILE%\.dpf\install-state.json. A container reads the host directory through /dpf-state with the mount access appropriate to its responsibility.
A previous-release state without capability fields migrates once to the documented pre-profile compatibility set: core, build, browser automation, durable automation, local speech, deep observability, and external AI. This preserves services that previously started by default without silently enabling newer optional capabilities. The adapter expands dependencies, writes the sorted keys and hashes through a sibling temporary file and atomic rename, and subsequent resolution rejects stale catalog or state hashes. Existing optional volumes and data are not deleted by migration or deactivation; deletion requires the separate evidence-approved removal process.
A fresh installer state carries an explicit empty capability selection, so its first projection activates only the always-on core dependency closure and writes the current hashes. Missing capability selection means legacy state; an explicit empty selection means a new core-only install. This distinction prevents compatibility migration from turning every clean install into the pre-profile full runtime.
Consumer installs no longer embed a second Compose topology. The Windows installer exports canonical release assets from the selected portal image, rejects missing, duplicate, path-escaping, unlisted, or SHA-256-mismatched files, and records a verified-asset manifest and release-version marker. Resume revalidates the installed asset bytes and version before binding .env. DPF_IMAGE_TAG and GHCR_OWNER are replaced atomically while unrelated operator settings and comments are preserved, so every image in docker-compose.release.yml resolves to the verified release version. The resolved project root and Compose file chain are canonicalized for child processes so a wrapper cannot validate one installation and execute another.
Governed self-upgrade carries the enabled capability snapshot forward and recomputes its projection against the release catalog before service replacement. The promotion recovery path copies the prior install state before mutation and restores that file atomically after a failed promotion; the governed rollback workflow owns restoration of the prior deployed release and PostgreSQL recovery point. Normal upgrades use /ops/self-upgrade; direct rebuilds of the live portal are not a supported upgrade path.
Backup and health semantics
PostgreSQL remains the mandatory scheduled core backup and trial-restore target. For enabled non-core services, backupPolicy: included means their canonical data is already covered by the core backup owner; separate-required means the projection selects the target but a dedicated runner must exist. A selected separate-required target without a runner reports optional_degraded. Disabled targets receive an optional_inactive receipt and do not create an independent failing schedule. External provider runtimes are never local backup targets. The retired BET-5 graph and vector backup schedules remain deactivated; this capability work does not resurrect them.
The shared health projector exposes four explicit states:
| State | Meaning and aggregate effect |
|---|---|
| Required | Desired local service. Missing or unhealthy makes aggregate health degraded. |
| Optional — inactive | Capability is disabled. Absence is expected and does not degrade aggregate health. |
| Optional — degraded | Capability is enabled but its service or required backup runner is unavailable; aggregate health is degraded. |
| External — provider managed | Provider configuration and reconciled provider evidence determine availability; it is not treated as a local container. |
Observations for services or providers absent from the catalog are rejected. External provider probes are bounded and failure-isolated, retain useful disabled-provider diagnostics, and cannot turn an unrelated provider batch failure into fabricated local service state. The UI uses text, icons, details, and actions in addition to theme-aware color.
Observation and diagnostics boundary
The portal observes only containers in its own Docker Compose project. It discovers that project from the current container label, queries Docker Engine through the mounted socket with a five-second timeout and one-megabyte response limit, and maps Compose service labels plus container/health state into the operational projection. A missing hostname, missing project label, inaccessible engine, timeout, oversized response, or malformed response yields no observations; the projector then reports the applicable required or optional degradation instead of guessing.
Host diagnostics remain in installer-owned doctor and verification surfaces. They record the canonical Compose file chain, rendered configuration hash, container state, and redacted install state. Docker Engine itself is a host prerequisite and observation boundary, not a manifest service. Podman command aliases are rejected by installer preflight because the current contract requires standard Docker Engine.
Diagnosing capability drift (BI-5ACBAC50)
Two authorities describe what is enabled: enabledRuntimeCapabilities in
install-state.json, and PlatformCapability.state in the database. The
transition protocol keeps them together — live state commits only after the
signed host receipt proves the topology.
When they disagree anyway, projectCapabilityServices throws
capability_state_stale:<capabilityId> and refuses to project. That is
deliberate: a projection that guessed which side to believe would hand backup,
readiness and the health UI a topology neither source claims.
The refusal used to name only the FIRST mismatch, and it happens inside the
loader that runtime health and backup readiness call — so the surfaces that would
explain the condition were the ones that could not render.
createOperationalCapabilityState now re-raises that error with the full
diagnosis from
capability-state-divergence.ts:
every drifted capability, and which way each drifted.
live-active-not-enabled— the database says on, the install snapshot does not list it. Anything trusting capability state believes services are running that the install never provisioned. This is the shape that let an installation reportruntime:deep-observabilityactive while no collector existed, so every metric-backed surface had no source and the state that would have revealed it read healthy.enabled-not-live-active— the install enabled it, the database says disabled. The services may be running while the platform believes they are not, so nothing tends them.missing-live-state— no capability row at all.
Reporting is not repair. The diagnosis says what diverged; it never decides which authority wins, because reconciling without first finding the writer that moved state outside the transition protocol leaves the cause in place.
Existing-install reconciliation — BI-5ACBAC50
The current implementation supports version 2 reconciliation with distinct,
complete host and database baselines, immutable packaged code identity, touched-only
database updates, and persisted compensation. Preview reports disagreement without
choosing desired settings; apply requires an explicit request. Browser actions
authorize the session’s manage_platform capability. Governed MCP checks the same
capability and existing token/coworker grants, then passes its authenticated user
to the shared command service; a browser cookie is not an MCP prerequisite.
The backend checkpoint passed all six real PostgreSQL cases and its canonical gate; PR 6366 also passed protected integration and merged. Those are source and cloud proofs. Canonical deployment and live reconciliation remain separate acceptance gates, and no native review verdict is implied.
The bounded design passed independent review; implementation is in progress and has not run on an installation. It completes the remaining reconciliation scope of BI-5ACBAC50, using the existing transition coordinator, host authority, receipt ledger and operational projection. It does not reopen the broader substrate workstreams.
On served revision f881fcb84de1bb07748f017ce07ecb85042507ac, the mounted host
snapshot enables core only while the database retains the optional capabilities’
seed-active values. There are no runtime transition rows. SUR-885E9856’s recorded
required services exactly match the read-only host projection and omit sandbox;
the promoter therefore skips its sandbox-refresh step. Its portal succeeded,
but that result does not qualify the sandbox image or CLI. The existing item’s
August 27 diagnosis already explains the disagreement at initial seeding.
The normal transition is deliberately unable to repair this baseline: its previous keys and hash come from live database state, while the host verifies them against its persisted snapshot. Do not remove that refusal, overwrite the snapshot, flip database rows, or enable every seed-active capability.
Decision DI-375608F0065D selects an explicit dual-baseline reconciliation over
a separate correction followed by ordinary activation. The platform consult was
usable, high confidence and autonomy eligible with no commandment conflict.
This chooses a source architecture, not a desired live capability set.
Contract. Extend the existing transition with an explicit reconciliation mode. Bind the actual validated host enabled set, catalog/state hashes and identity separately from the complete observed database capability-state map. The durable request, signed envelope and idempotent replay must cover both baselines and the explicit proposed desired results. Ordinary transitions retain their consistency precondition. A changed baseline, unknown key, stale catalog, unreadable host state or unknown operator intent refuses the apply with a specific recovery result rather than assuming either authority wins.
Normalize unproven seed claims only through this reviewed transition. Maintain separate desired host-enabled keys and a desired database-state map, with an explicit set of managed/touched capability keys. Derive host changes from the verified snapshot plus explicitly requested capabilities. Preserve every untouched database value; do not infer intent from a seed default or a running leftover container. Bind both desired results and the touched keys in the signed request and durable replay identity. A preview names EVERY changed database state and physical service, kept volumes, health requirements, remaining disagreement and rollback target. Unknown unrelated intent remains unchanged with explicit residual drift, or receives a real decision before any normalization. A partial repair never claims global agreement. A single global desired set is unsafe.
Integrity. Source revision 1cf5311615da456dff8679d1d112b2237cb7c280
reproduces a prerequisite defect: the legacy signature serializer drops nested
observedHealth members, so changing unhealthy to healthy retains its signature.
A versioned envelope and receipt must recursively bind every baseline and health
value through the shared signing implementation. The standalone host must use
that same implementation. Reconciliation requires BOTH server and host to support
version 2. Unknown or older versions refuse BEFORE authority reservation, journal
creation or state mutation; there is no fallback to version 1. Deliver the shared
verifier and actuator in the verified canonical promoter image closure:
promote.sh executes its packaged actuator and signing module, rather than the
host install’s script copy. Run a read-only protocol/version probe on that exact
immutable image and compare its source identity with the server before enabling
reconciliation. Installer-owned client assets still converge through their normal
release path; a portal image swap does not prove those files changed. A missing
delivery path is a source blocker, never permission for an ad hoc installed copy.
Preserve historical legacy parsing with an explicit unverified-health disposition; an old signature cannot establish newly verified health. Never relabel historical records as tampered merely because they predate the stronger format, and never promote their unsigned fields into live evidence. A legacy receipt may not be replayed into a fresh version 2 reconciliation.
Execution. Reuse the existing transition authority lock, serializable database admission, host apply journal, bounded lease and signed receipt. Admission compares the observed database baseline inside its transaction; host apply compares the observed host baseline inside its existing guarded write. Database success occurs only after the exact desired topology and required health are independently observed. Compensation compares against THIS saga’s applied host snapshot and managed database values before restoring the actual observed prior topology and database values. It must never overwrite a subsequent writer: changed ownership, hash or touched value reports recovery-required instead of forcing rollback. Untouched values remain untouched. Record any restored baseline disagreement truthfully. A stale or interrupted request resumes only its own bound journal; it cannot adopt another owner’s receipt. Keep authority, credential and destructive confirmation gates.
Ordered delivery and qualification.
- Reproduce seeded initial disagreement, ordinary-transition refusal, and nested-signature omission on the named source. Record source proof separately from the read-only live observations and native initiative receipts.
- Qualify versioned recursive signing and shared host verification first: nested health/baseline/desired-result/touched-key tampering, key ordering, host/server capability probes, mixed or unknown versions before any mutation, old flat envelopes and truthful legacy historical reads.
- Extend the existing coordinator and host apply boundary with dual baseline validation, replay identity and compensation. Exercise two concurrent writers, drift between preview/admission/apply, wrong owner, expired launch, crash at each durable boundary and failed required health against real persistence.
- Correct fresh bootstrap claims through host-grounded activation; preserve existing operator state during registry sync. Define the old-install migration stance explicitly, including retained ephemeral build and development services.
- Expose the same governed preview and actuator to supported clients; add no second transition engine or independent writer. Reuse the existing runtime health projection and shared disclosure/table/status components.
- Publish through independent source review, DCO, protected checks and one canonical image producer. After deployment, perform one authorized transition and verify agreement, exact sandbox image/CLI and subsequent upgrade behavior. The expected DEV build capability is not declared active by this document.
At least 20% of this repair consolidates duplicated projection, signing and baseline validation. No source test, consultation, merged PR or healthy portal substitutes for the live reconciliation and build-engine acceptance.
Historical implementation evidence
The following incremental notes preserve earlier test results and the boundaries that existed at each checkpoint. Their statements about unimplemented modes or pending source qualification are superseded by the current contract above; they do not describe the latest source or establish live acceptance.
The first signing regression reproduced two failures before the repair, then passed all 13 shared-signing tests. The host actuator now imports that same signer; its ten existing crash, rollback, schema, expiry and health tests pass. The expired-envelope fixture now supplies its own temporary state directory so it cannot contend with another test or install’s apply lock. All 54 related protocol/coordinator/upgrade preflight tests pass. These are source proofs only: version 2 apply, compatibility probes, dual-baseline admission, compensation, canonical release and live reconciliation are still unqualified.
Independent review then reproduced a malformed version 2 payload without its kind falling back to legacy signing. Both direct signing and live/historical receipt verification regressions failed before correction. Version 2 now refuses a missing or wrong kind before serialization; the corrected shared/host suite passes 24 tests and the related protocol suite passes 55. This review finding does not establish a live exploit or qualify version 2 application.
The read-only packaged probe now reports signing, apply and reconciliation support separately, alongside its source label and actuator/signer byte hashes. Its command uses the validated immutable image without host mounts, secrets, Docker socket or network, and bounds memory/CPU. The actual shell entrypoint and direct actuator tests verify that a probe leaves its state directory empty and refuses mixed probe/apply arguments. The probe advertises apply version 1 and no reconciliation support until implementation qualifies them. All 26 shared/host tests and 205 related promoter/protocol/coordinator/upgrade tests pass. No live image probe, admission integration, full gate or reconciliation is claimed.
Before executing an image probe, its command also bounds PIDs and forbids an implicit pull; the verified artifact must already be present. The protocol reader requires the trusted source SHA and both expected byte digests, rejects malformed or contradictory version sets, and does not infer apply support from signing support. Its expected identities must come from the verified canonical server/candidate closure, never caller-provided policy claims. The existing owned-container timeout/fencing runner remains required when this discovery is wired into admission. Source tests do not establish that runtime wiring.
The actuator now accepts version 2 ordinary transitions with an explicit
mode: transition, preserving the existing consistent-baseline precondition.
Its receipts recursively authenticate observed health; source fixtures exercise
replay and every existing durable crash boundary in both versions. A signed
mode: reconciliation still refuses before any journal or install-state write.
The packaged probe therefore advertises apply versions 1 and 2, and no
reconciliation support. The server coordinator still issues version 1 until
trusted packaged-probe admission is wired. These source prerequisites do not
qualify dual-baseline application, legacy health evidence or a live transition.
The packaged discovery runner now uses the existing owned-container process budget, with a 60-second limit and 4 KiB stdout ceiling. It checks server/image source agreement before execution, then validates the reported source and byte digests through the shared protocol reader. Failed execution, timeout, output overrun, malformed output or contradictory support cannot supply evidence. Eight new source regressions failed before this runner existed, then all 198 related promoter, protocol, coordinator and upgrade tests passed. The caller must still obtain expected digests from the trusted server closure and wire discovery before reconciliation admission; no actual image probe or live apply is claimed.
The host actuator also uses the already-packaged shared capability-state hash helper instead of maintaining its own serialization. This preserves the existing ordinary-transition hash and consistent-baseline requirement. The existing hash, signing, host crash/recovery and promoter closure suites pass 45 source tests; this refactor supplies no live capability or reconciliation evidence.
The coordinator now snapshots caller identity and complete state maps before asynchronous projection. Durable admission compares the complete observed database baseline inside its serializable transaction; replay also compares the original requester and both complete state maps. Seven preserved regressions failed before this repair, then all 114 tests across three executed affected files passed. Both official web TypeScript programs passed. These are source prerequisite checks: the packaged reconciliation mode, owned compensation, bootstrap synchronization, real PostgreSQL qualification and live agreement remain unverified. No capability was activated by these checks.
Safe operating rules
Runtime Health keeps active required, degraded and provider-managed service requirements visible. Known inactive optional services remain available in a collapsed, keyboard-operable disclosure; they do not reduce platform health. Identical required-service recovery advice is shown once, while distinct actions and provider navigation remain visible. This presentation preserves the canonical health projection and every service record; it changes neither capability intent nor observed availability.
When all active entries are required services with the same availability and
status, one visible status describes the group. Each service references that
status with aria-describedby; its name, details and actions remain individual.
Mixed, degraded and provider-managed groups keep individual status labels. Static
view copy uses the request’s existing admin translator, with the same catalog
provided to the product-health client view.
- Change physical service facts in the substrate manifest and regenerate the catalog; do not hand-edit the generated catalog.
- Change capability dependencies or activation policy in the canonical capability seed/sync path; do not encode them in Compose.
- Change enabled state only through the governed transition API/saga. Do not set
COMPOSE_PROFILESto bypass capability authority. - Preserve lifecycle overlays as explicit operator intent and capability profiles as resolved state.
- Treat a stale hash, unknown capability, unknown observation, or failed receipt as an operator-visible fault. Do not infer a replacement state.
- Retire a capability in two phases — mark it
retiredand leave the entry for a release, then delete it. Deleting the entry outright wedges every install that still has it enabled. - Use governed self-upgrade and its recovery point for release changes; do not mutate the live topology with an ad hoc Compose rebuild.
- Do not remove optional volumes, schedules, or provider records merely because a capability is inactive.
How self-upgrade may recreate a service
Every service in every shipped compose file declares, where it is defined, how the self-upgrade promoter may converge it when its rendered config changes:
labels:
dpf.recreate-class: stateless # or data-owner, managed
statelessservices are recreated after the portal swap when their config hash differs. Their volumes are kept.data-ownerservices (the Postgres instances, Redis and the certificate authority) are recreated only when changed, before the swap, behind the recovery point.managedservices (portal, sandbox, init jobs, the promoter, and the dev and CI portals) keep their own lifecycle steps.
Overlay services that the capability catalog does not model, such as portal-tls, carry the label too. check-no-unclassified-compose-services.mjs fails on a missing, unknown or conflicting class. The design is running-service compose convergence (BI-C54E691E).
The executable conformance checks are check-capability-compose-profiles.mjs, the resolver tests, installer/lifecycle contract tests, and the substrate ratchet described in Platform substrate boundaries and budgets.