Health, logs, and resource intelligence
Phase 7 implements ADR-0014 as a boundary above both runtime drivers. Docker and native-process adapters still emit raw runtime observations and log lines; they do not own retention, health policy, redaction, or browser state.
Log pipeline
Docker/process raw stream | vcanonical redactor | +--> bounded per-service ring +--> rotating private NDJSON segment +--> live WebSocket subscribers +--> query/export APIsThe redactor runs before every sink. Built-in rules cover bearer credentials,
secret-like environment assignments, credential-bearing URLs, and common
access-key forms. Repeated switchyard daemon --redact-pattern flags add local
regular expressions. Resolved keychain values are registered with the redactor
in memory at launch and are never written as redaction configuration.
SQLite stores segment identity, run and operation correlation, line indexes,
time/sequence ranges, sizes, and checksums. Log content remains in mode 0600
NDJSON files below the private data directory. A SQLite transaction remains
uncommitted until its corresponding line is appended, so queries never observe
an index ahead of the file. Stable content digests discard the initial-tail
overlap produced when a collector reconnects.
Segments rotate by byte cap. Closed segments have SHA-256 checksums and are deleted oldest-first by both age and aggregate byte cap. File deletion is staged so a failed metadata update can restore the original path, and startup repairs interrupted staged deletions. Compression, full-text search, and cross-project analytics remain outside this phase.
GET /api/v1/projects/{projectId}/logs queries the persisted stream by service,
run, operation, time, and tail limit. The export endpoint emits already-redacted
plain text or NDJSON. /ws/v1/logs subscribes before replay, resumes after a
durable sequence, and removes replay/live overlap before delivery. Subscriber
overflow closes the socket so the same cursor protocol can recover the gap.
Health evaluation
Trusted manifests can declare HTTP status and JSON-path assertions, TCP
connects, process-alive checks, Docker health, shell-free commands, and
composite all/any checks. Each declaration has an ID plus initial delay,
interval, timeout, retry count, severity, and required flag. HTTP and TCP checks
are loopback-only at both manifest validation and execution.
The scheduler:
- applies initial delay and stable per-project jitter;
- honors the shortest configured interval in each project;
- evaluates up to four projects concurrently;
- gives every individual probe a strict context deadline;
- re-observes Docker/process state between readiness retries;
- persists bounded, sanitized results and cancels with daemon shutdown.
Lifecycle start, restart, and rebuild operations execute first, then wait for
required checks. A readiness failure fails the operation but does not stop or
misclassify the running service. The HTTP runtime view overlays degraded only
when a required or non-informational health result is unhealthy. The health response
separately marks observations as connected, stale, or disconnected.
UI behavior
The project diagnostics view shows runtime services, health results, observer freshness, and a persisted/live log preview. Log rows are keyed by durable sequence. The browser reconnects with its last sequence, merges the HTTP snapshot with WebSocket replay, and deduplicates overlap. Disconnected and stale observations remain visible as warnings rather than being rendered as a false stopped or healthy state.
Resource sampling and history
Phase 12 extends the same bounded context with one process-wide sampler:
trusted catalog descriptors | vbounded active-runtime observation ----> current project/service aggregate | | v vexact SQLite samples -> 1-minute -> 15-minute -> bounded history APIRuntime drivers provide raw provider-neutral samples. Compose contributes one sample per canonical labelled container, including replicas. The native driver aggregates every currently verified member of a durable managed process tree. The observability application layer performs project/service aggregation and budget evaluation; neither driver owns history or warning policy.
Every potentially missing metric has explicit availability evidence. A partial container/process read remains a gap and is never coerced into a convincing zero. Rollups average only available CPU, memory, and health values, retain peaks, keep the latest available cumulative network/disk/storage evidence, and carry partial status forward.
Default tiers are exact samples every ten seconds for one hour, one-minute samples for 24 hours, and fifteen-minute samples for 30 days. Rollups are idempotent and source data is pruned only after the target upsert commits. History requests select a retained tier and enforce a hard point cap.
Storage intelligence boundary
The Docker adapter uses Engine disk-usage APIs only. Its consumer-owned interface exposes inspection and has no prune/delete method. Canonical Compose project labels and live image/volume references are the only project evidence; names and path prefixes are never guessed.
Container writable layers may be exclusive when one canonical project owns them. Volumes are exclusive only with local size and single-project evidence. Images remain estimated or shared because layer exclusivity is not proven. Build cache is shared or unknown. Every record includes its classification and reason, and Switchyard’s database/WAL/SHM/log footprint is reported separately as Switchyard-exclusive storage.
Cleanup preview is a read model containing exact Engine identifiers and known or unknown reclaimable bytes. It is always non-executable; Phase 12 adds no automatic deletion surface.