fix(runtime): keep shared artifacts optional

This commit is contained in:
DCCONSTRUCTIONS
2026-07-30 23:14:50 +03:00
parent 8c91d40e2e
commit dee6d57133
7 changed files with 72 additions and 33 deletions
@@ -64,7 +64,10 @@ separate future gate.
`GET /api/v1/device-plugin-runtimes` exposes the small lifecycle snapshots. The
main health response includes ready/total runtime counts as one component beside
recording-cache, shared-artifact, media-tool and catalog-reconciler readiness.
recording-cache, optional shared-artifact capability, media-tool and
catalog-reconciler readiness. A missing optional shared-artifact provider does
not degrade the complete local contour.
The plugin values still do not claim device connectivity, sensor health,
process containment or durable supervision.
+1 -1
View File
@@ -78,7 +78,7 @@ Contour health reads only live contracts:
- current Mission Runtime state for active device and perception metrics.
The base health contract now separates local operational readiness from
production shared-artifact readiness and reports bounded cache, catalog
optional shared-artifact capability and reports bounded cache, catalog
reconciler, media-tool and Map Gateway configuration states. It performs no
remote fan-out and never invents Worker 006 or device health.
@@ -5,17 +5,18 @@ Status: accepted and implemented
## Decision
Mission Core stores portable recorded-session products in a provider-neutral,
content-addressed artifact store. The current central provider is the existing
Synology SMB mount:
Mission Core can exchange portable recorded-session products through an
optional provider-neutral, content-addressed artifact gateway. The canonical
current operator contour is local and complete without a shared store. An
external filesystem provider is an auxiliary transport/prefetch capability,
not an operational-readiness dependency and not a production topology
decision.
```text
/Volumes/docker/nodedc-mission-core/artifact-store
```
This is product runtime data. It is not a deploy artifact, a Map Gateway cache,
a Device Plane package, or a new Docker service. Authentication remains owned
by the operating-system SMB mount; Mission Core does not receive a NAS password.
The historical RAVNOVES00 migration acceptance used an existing SMB-backed
filesystem as one experimental provider. That provider, its mount and its host
configuration are outside the current Mission Core runtime contract. Mission
Core does not own its authentication, does not require it at startup and does
not receive a NAS password.
Every immutable object is stored under:
@@ -55,7 +56,7 @@ MISSIONCORE_ARTIFACT_CACHE_MAX_BYTES
MISSIONCORE_ARTIFACT_CACHE_FREE_SPACE_RESERVE_BYTES
```
The central root is configured with:
An optional shared root is configured explicitly with:
```text
MISSIONCORE_ARTIFACT_STORE_ROOT
@@ -115,16 +116,19 @@ When the central root is unavailable:
`GET /api/health` exposes the effective shared/standalone mode, central-store
availability, bounded CAS and RRD-cache occupancy, media-tool availability and
the background catalog reconciler state without disclosing filesystem paths.
Operational readiness remains distinct from production shared-artifact
readiness so an offline, already pinned field host stays observable rather than
being mistaken for a fully connected host.
`GET /api/health` reports local operational readiness independently. Optional
shared artifacts are exposed as a non-required capability with separate
`configured` and `ready` values. Their absence or temporary unavailability does
not degrade a healthy local contour. When an operator explicitly configures
that capability, its fail-closed cache-miss semantics still apply to artifacts
that were expected from the configured gateway.
## RAVNOVES00 migration acceptance
The source session is `20260720T065719Z_viewer_live`, displayed as
`RAVNOVES00`.
The accepted central reference currently points to:
The reference used by that bounded migration acceptance pointed to:
```text
092f758c09965be98fd76d8191474c528ee20540dce5f4761c2a087f6056a6d5
+1 -1
View File
@@ -1,4 +1,4 @@
"""Operator commands for the Mission Core central artifact gateway."""
"""Operator commands for the optional Mission Core artifact gateway."""
from __future__ import annotations
+1 -1
View File
@@ -1,4 +1,4 @@
"""Content-addressed central artifacts with a bounded, offline-capable host cache."""
"""Optional content-addressed artifact exchange with a bounded local cache."""
from __future__ import annotations
+8 -11
View File
@@ -100,8 +100,9 @@ def build_runtime_readiness(
"central_available": None,
}
shared_artifacts_ready = False
shared_artifact_degraded = False
shared_artifacts_configured = False
else:
shared_artifacts_configured = True
try:
artifact = artifact_gateway.status()
cache = artifact.cache
@@ -127,7 +128,6 @@ def build_runtime_readiness(
},
}
shared_artifacts_ready = artifact.central_status == "ready"
shared_artifact_degraded = not shared_artifacts_ready
except (OSError, RuntimeError):
artifact_document = {
"mode": "shared",
@@ -135,7 +135,6 @@ def build_runtime_readiness(
"central_available": False,
}
shared_artifacts_ready = False
shared_artifact_degraded = True
media_tools_ready = ffmpeg_available and ffprobe_available
reconciler_document = reconciler.snapshot()
@@ -151,11 +150,7 @@ def build_runtime_readiness(
and media_tools_ready
and reconciler_failures < 3
)
degraded = (
shared_artifact_degraded
or reconciler_failures > 0
or not operational_ready
)
degraded = reconciler_failures > 0 or not operational_ready
status = (
"unavailable"
if not operational_ready
@@ -170,9 +165,11 @@ def build_runtime_readiness(
"version": version,
"readiness": {
"operational": operational_ready,
"production_shared_artifacts": (
operational_ready and shared_artifacts_ready
),
"optional_shared_artifacts": {
"required": False,
"configured": shared_artifacts_configured,
"ready": shared_artifacts_ready,
},
},
"plugin_runtimes": {
"ready": ready_runtime_count,
+38 -3
View File
@@ -57,7 +57,11 @@ def test_runtime_readiness_reports_shared_store_and_bounded_cache(
assert document["status"] == "ok"
assert document["readiness"] == {
"operational": True,
"production_shared_artifacts": True,
"optional_shared_artifacts": {
"required": False,
"configured": True,
"ready": True,
},
}
components = document["components"]
assert isinstance(components, dict)
@@ -85,16 +89,47 @@ def test_runtime_readiness_exposes_offline_cache_only_mode(
document = _document(tmp_path, gateway=gateway, reconciler=reconciler)
assert document["ok"] is True
assert document["status"] == "degraded"
assert document["status"] == "ok"
assert document["readiness"] == {
"operational": True,
"production_shared_artifacts": False,
"optional_shared_artifacts": {
"required": False,
"configured": True,
"ready": False,
},
}
components = document["components"]
assert isinstance(components, dict)
assert components["artifact_store"]["status"] == "offline-cache-only"
def test_runtime_readiness_treats_standalone_as_complete_local_contour(
tmp_path: Path,
) -> None:
reconciler = BackgroundReconcilerReadiness()
reconciler.record_success()
document = _document(tmp_path, gateway=None, reconciler=reconciler)
assert document["ok"] is True
assert document["status"] == "ok"
assert document["readiness"] == {
"operational": True,
"optional_shared_artifacts": {
"required": False,
"configured": False,
"ready": False,
},
}
components = document["components"]
assert isinstance(components, dict)
assert components["artifact_store"] == {
"mode": "standalone",
"status": "not-configured",
"central_available": None,
}
def test_runtime_readiness_fails_after_repeated_reconciler_errors(
tmp_path: Path,
) -> None: