diff --git a/apps/api/src/services/ai_agent_autonomous_runtime_control.py b/apps/api/src/services/ai_agent_autonomous_runtime_control.py
index 8e97dc9d3..a06f9fc5b 100644
--- a/apps/api/src/services/ai_agent_autonomous_runtime_control.py
+++ b/apps/api/src/services/ai_agent_autonomous_runtime_control.py
@@ -7190,6 +7190,19 @@ async def _load_core_runtime_receipt_rows_direct(
return None
+def build_ai_agent_strict_runtime_completion_from_readback(
+ readback: Mapping[str, Any],
+) -> dict[str, Any]:
+ """Project the canonical strict completion contract from one readback."""
+
+ payload = build_ai_agent_autonomous_runtime_control()
+ _attach_runtime_receipt_readback(payload, dict(readback))
+ strict_runtime = payload.get("strict_runtime_completion")
+ if not isinstance(strict_runtime, Mapping):
+ return {}
+ return copy.deepcopy(dict(strict_runtime))
+
+
async def build_ai_agent_autonomous_runtime_control_with_live_readback(
*,
project_id: str = _DEFAULT_PROJECT_ID,
diff --git a/apps/api/src/services/iwooos_security_asset_control_plane.py b/apps/api/src/services/iwooos_security_asset_control_plane.py
index 68ed4315b..24396cd77 100644
--- a/apps/api/src/services/iwooos_security_asset_control_plane.py
+++ b/apps/api/src/services/iwooos_security_asset_control_plane.py
@@ -3,7 +3,7 @@
from __future__ import annotations
import asyncio
-from collections.abc import Iterable
+from collections.abc import Iterable, Mapping
from datetime import UTC, datetime
from typing import Any
@@ -11,16 +11,27 @@ import structlog
from sqlalchemy import text as _sql
from src.db.base import get_db_context
+from src.services.ai_agent_autonomous_runtime_control import (
+ build_ai_agent_strict_runtime_completion_from_readback,
+ load_ai_agent_autonomous_runtime_receipt_readback,
+)
+from src.services.ai_automation_runtime_contract import (
+ AI_AUTOMATION_REQUIRED_LOOP_STAGES,
+ AI_AUTOMATION_RUNTIME_CONTRACT_SCHEMA_VERSION,
+)
logger = structlog.get_logger(__name__)
_SCHEMA_VERSION = "iwooos_security_asset_control_plane_v1"
_QUERY_TIMEOUT_SECONDS = 12.0
_SOURCE_QUERY_TIMEOUT_SECONDS = 3.0
+_STRICT_RUNTIME_SOURCE_TIMEOUT_SECONDS = 8.5
_SOURCE_CONCURRENCY = 3
_CACHE_TTL_SECONDS = 30.0
_DISCOVERY_FRESHNESS_SECONDS = 2 * 60 * 60
_WINDOW_HOURS = 24
+_STRICT_RUNTIME_SCHEMA_VERSION = "ai_agent_strict_runtime_completion_v2"
+_STRICT_RUNTIME_SOURCE_ID = "autonomous_strict_runtime"
_ASSET_TYPES = (
"host",
@@ -685,6 +696,126 @@ def _work_item(
}
+def _strict_runtime_completion_projection(row: Any) -> dict[str, Any]:
+ """Validate and reduce the authoritative same-run contract for public use."""
+
+ strict = row if isinstance(row, Mapping) else {}
+ expected_stage_ids = set(AI_AUTOMATION_REQUIRED_LOOP_STAGES)
+ required_stage_count = len(AI_AUTOMATION_REQUIRED_LOOP_STAGES)
+ reported_required_count = strict.get("required_stage_count")
+ reported_present_count = strict.get("present_stage_count")
+ missing_stage_ids = strict.get("missing_stage_ids")
+ mismatch_stage_ids = strict.get("run_id_mismatch_stage_ids")
+ uncorrelated_stage_ids = strict.get("uncorrelated_stage_ids")
+ stage_contracts = strict.get("stage_contracts")
+
+ valid_counts = bool(
+ isinstance(reported_required_count, int)
+ and not isinstance(reported_required_count, bool)
+ and reported_required_count == required_stage_count
+ and isinstance(reported_present_count, int)
+ and not isinstance(reported_present_count, bool)
+ and 0 <= reported_present_count <= required_stage_count
+ )
+ valid_missing = bool(
+ isinstance(missing_stage_ids, list)
+ and all(isinstance(stage_id, str) for stage_id in missing_stage_ids)
+ )
+ valid_mismatch = bool(
+ isinstance(mismatch_stage_ids, list)
+ and all(isinstance(stage_id, str) for stage_id in mismatch_stage_ids)
+ )
+ valid_uncorrelated = bool(
+ isinstance(uncorrelated_stage_ids, list)
+ and all(isinstance(stage_id, str) for stage_id in uncorrelated_stage_ids)
+ )
+ valid_stage_contracts = False
+ if (
+ isinstance(stage_contracts, list)
+ and len(stage_contracts) == required_stage_count
+ ):
+ stage_ids = {
+ str(stage.get("stage_id") or "")
+ for stage in stage_contracts
+ if isinstance(stage, Mapping)
+ }
+ valid_stage_contracts = bool(
+ stage_ids == expected_stage_ids
+ and all(
+ isinstance(stage, Mapping)
+ and stage.get("evidence_present") is True
+ and stage.get("same_run_correlation_proven") is True
+ and stage.get("completion_eligible") is True
+ for stage in stage_contracts
+ )
+ )
+
+ contract_compatible = bool(
+ strict.get("schema_version") == _STRICT_RUNTIME_SCHEMA_VERSION
+ and strict.get("runtime_contract_schema_version")
+ == AI_AUTOMATION_RUNTIME_CONTRACT_SCHEMA_VERSION
+ and valid_counts
+ and valid_missing
+ and valid_mismatch
+ and valid_uncorrelated
+ and isinstance(stage_contracts, list)
+ and len(stage_contracts) == required_stage_count
+ )
+ same_run_closed_loop_proven = bool(
+ contract_compatible
+ and valid_stage_contracts
+ and strict.get("completion_percent") == 100
+ and reported_present_count == required_stage_count
+ and missing_stage_ids == []
+ and strict.get("latest_flow_closed") is True
+ and strict.get("latest_loop_closed") is True
+ and strict.get("execution_loop_closed") is True
+ and strict.get("same_run_correlation") is True
+ and strict.get("full_trace_same_run_correlation_proven") is True
+ and bool(str(strict.get("automation_run_id") or "").strip())
+ and mismatch_stage_ids == []
+ and uncorrelated_stage_ids == []
+ and strict.get("closed") is True
+ and strict.get("same_run_correlation_required") is True
+ and strict.get("metadata_only_counts_as_completion") is False
+ and strict.get("historical_aggregate_fallback_allowed") is False
+ )
+ present_stage_count = reported_present_count if valid_counts else 0
+ missing_stage_count = (
+ len(missing_stage_ids)
+ if valid_missing
+ else required_stage_count - present_stage_count
+ )
+ if not strict:
+ reason_code = "strict_runtime_source_unavailable"
+ elif not contract_compatible:
+ reason_code = "strict_runtime_contract_mismatch"
+ elif not same_run_closed_loop_proven:
+ reason_code = "strict_runtime_receipts_incomplete"
+ else:
+ reason_code = None
+
+ return {
+ "schema_version": _STRICT_RUNTIME_SCHEMA_VERSION,
+ "runtime_contract_schema_version": (
+ AI_AUTOMATION_RUNTIME_CONTRACT_SCHEMA_VERSION
+ ),
+ "contract_compatible": contract_compatible,
+ "completion_percent": 100 if same_run_closed_loop_proven else 0,
+ "required_stage_count": required_stage_count,
+ "present_stage_count": present_stage_count,
+ "missing_stage_count": missing_stage_count,
+ "same_run_correlation": same_run_closed_loop_proven,
+ "full_trace_same_run_correlation_proven": same_run_closed_loop_proven,
+ "execution_loop_closed": same_run_closed_loop_proven,
+ "closed": same_run_closed_loop_proven,
+ "reason_code": reason_code,
+ "cache_fallback_active": strict.get("_cache_fallback_active") is True,
+ "raw_run_identity_returned": False,
+ "raw_stage_receipts_returned": False,
+ }
+
+
def build_iwooos_security_asset_control_plane(
*,
discovery_row: Any,
@@ -696,6 +827,7 @@ def build_iwooos_security_asset_control_plane(
ai_trace_row: Any,
siem_row: Any,
audit_row: Any,
+ strict_runtime_row: Any = None,
source_health: Iterable[dict[str, Any]] | None = None,
generated_at: datetime | None = None,
) -> dict[str, Any]:
@@ -854,9 +986,10 @@ def build_iwooos_security_asset_control_plane(
for row in automation_source
if str(_value(row, "status", "")) == "failed"
)
- # Aggregate stage receipts cannot prove that every stage belongs to one
- # trace. Keep strict runtime completion closed until a same-run join exists.
- same_run_closed_loop_proven = False
+ strict_runtime_completion = _strict_runtime_completion_projection(
+ strict_runtime_row
+ )
+ same_run_closed_loop_proven = strict_runtime_completion["closed"] is True
relationship_count = int(_value(relationship_row, "relationship_count", 0) or 0)
orphan_asset_count = int(
@@ -1160,7 +1293,9 @@ def build_iwooos_security_asset_control_plane(
/ len(security_program_domains)
)
package_inventory_evidenced = by_type.get("package", 0) > 0
- strict_runtime_closure_percent = 100 if same_run_closed_loop_proven else 0
+ strict_runtime_closure_percent = int(
+ strict_runtime_completion["completion_percent"]
+ )
completion_dimensions = [
{
"dimension_id": "asset_scope",
@@ -1280,7 +1415,8 @@ def build_iwooos_security_asset_control_plane(
"rollback_receipt_count": rollback_receipts,
"failed_operation_count": failed_operations,
"same_run_closed_loop_proven": same_run_closed_loop_proven,
- "same_run_closed_loop_count": 0,
+ "same_run_closed_loop_count": 1 if same_run_closed_loop_proven else 0,
+ "strict_runtime_completion": strict_runtime_completion,
},
"security_audit": audit,
"supply_chain": {
@@ -1361,9 +1497,9 @@ def build_unavailable_iwooos_security_asset_control_plane(
"source_status": "live_database_unavailable",
"reason_code": reason_code,
"summary": {
- "source_count": 9,
+ "source_count": 10,
"ready_source_count": 0,
- "unavailable_source_count": 9,
+ "unavailable_source_count": 10,
"managed_asset_count": 0,
"expected_asset_type_count": len(_ASSET_TYPES),
"present_asset_type_count": 0,
@@ -1519,6 +1655,7 @@ def build_unavailable_iwooos_security_asset_control_plane(
"failed_operation_count": 0,
"same_run_closed_loop_proven": False,
"same_run_closed_loop_count": 0,
+ "strict_runtime_completion": _strict_runtime_completion_projection(None),
},
"security_audit": {
"k8s_execution_audit_count_24h": 0,
@@ -1573,6 +1710,7 @@ def build_unavailable_iwooos_security_asset_control_plane(
"ai_decision_trace",
"siem_runtime",
"audit_runtime",
+ _STRICT_RUNTIME_SOURCE_ID,
)
],
"work_items": [
@@ -1669,6 +1807,65 @@ async def _read_public_source(
}
+async def _read_strict_runtime_source() -> tuple[dict[str, Any], dict[str, Any]]:
+ """Read and project the canonical same-run receipt contract independently."""
+
+ try:
+ readback = await asyncio.wait_for(
+ load_ai_agent_autonomous_runtime_receipt_readback(
+ project_id="awoooi",
+ lookback_hours=_WINDOW_HOURS,
+ ),
+ timeout=_STRICT_RUNTIME_SOURCE_TIMEOUT_SECONDS,
+ )
+ db_read_status = str(readback.get("db_read_status") or "")
+ if db_read_status not in {"ok", "partial"}:
+ return {}, {
+ "source_id": _STRICT_RUNTIME_SOURCE_ID,
+ "status": "unavailable",
+ "reason_code": "autonomous_strict_runtime_readback_unavailable",
+ }
+ strict_runtime = build_ai_agent_strict_runtime_completion_from_readback(
+ readback
+ )
+ if (
+ strict_runtime.get("schema_version")
+ != _STRICT_RUNTIME_SCHEMA_VERSION
+ or strict_runtime.get("runtime_contract_schema_version")
+ != AI_AUTOMATION_RUNTIME_CONTRACT_SCHEMA_VERSION
+ ):
+ return {}, {
+ "source_id": _STRICT_RUNTIME_SOURCE_ID,
+ "status": "unavailable",
+ "reason_code": "autonomous_strict_runtime_contract_mismatch",
+ }
+ strict_runtime["_cache_fallback_active"] = (
+ readback.get("cache_fallback_active") is True
+ )
+ return strict_runtime, {
+ "source_id": _STRICT_RUNTIME_SOURCE_ID,
+ "status": "ready",
+ "reason_code": None,
+ }
+ except TimeoutError:
+ logger.warning("iwooos_security_asset_control_plane_strict_runtime_timeout")
+ return {}, {
+ "source_id": _STRICT_RUNTIME_SOURCE_ID,
+ "status": "unavailable",
+ "reason_code": "autonomous_strict_runtime_query_timeout",
+ }
+ except Exception as exc: # noqa: BLE001 - redact public source failures
+ logger.warning(
+ "iwooos_security_asset_control_plane_strict_runtime_unavailable",
+ error_type=type(exc).__name__,
+ )
+ return {}, {
+ "source_id": _STRICT_RUNTIME_SOURCE_ID,
+ "status": "unavailable",
+ "reason_code": "autonomous_strict_runtime_query_failed",
+ }
+
+
class IwoooSSecurityAssetControlPlaneService:
"""Read aggregate production security state with a bounded DB timeout."""
@@ -2057,6 +2254,7 @@ class IwoooSSecurityAssetControlPlaneService:
result_mode="one",
default={},
),
+ _read_strict_runtime_source(),
)
(
@@ -2069,6 +2267,7 @@ class IwoooSSecurityAssetControlPlaneService:
(ai_trace_row, ai_trace_health),
(siem_row, siem_health),
(audit_row, audit_health),
+ (strict_runtime_row, strict_runtime_health),
) = source_results
source_health = [
discovery_health,
@@ -2080,6 +2279,7 @@ class IwoooSSecurityAssetControlPlaneService:
ai_trace_health,
siem_health,
audit_health,
+ strict_runtime_health,
]
return build_iwooos_security_asset_control_plane(
@@ -2092,6 +2292,7 @@ class IwoooSSecurityAssetControlPlaneService:
ai_trace_row=ai_trace_row,
siem_row=siem_row,
audit_row=audit_row,
+ strict_runtime_row=strict_runtime_row,
source_health=source_health,
)
diff --git a/apps/api/tests/test_ai_agent_autonomous_runtime_control.py b/apps/api/tests/test_ai_agent_autonomous_runtime_control.py
index 6b2e00233..0d5cf28fc 100644
--- a/apps/api/tests/test_ai_agent_autonomous_runtime_control.py
+++ b/apps/api/tests/test_ai_agent_autonomous_runtime_control.py
@@ -16,6 +16,7 @@ from src.services.ai_agent_autonomous_runtime_control import (
_RUNTIME_TIMELINE_COUNTS_SQL,
_runtime_stage_receipt_has_required_proof,
build_ai_agent_autonomous_runtime_control,
+ build_ai_agent_strict_runtime_completion_from_readback,
build_runtime_receipt_readback_from_rows,
classify_deploy_control_plane_observation,
)
@@ -1882,6 +1883,9 @@ def test_ai_agent_autonomous_runtime_control_uses_current_owner_directive():
assert strict["metadata_only_counts_as_completion"] is False
assert strict["historical_aggregate_fallback_allowed"] is False
assert len(strict["stage_contracts"]) == len(AI_AUTOMATION_REQUIRED_LOOP_STAGES)
+ assert build_ai_agent_strict_runtime_completion_from_readback(
+ data["runtime_receipt_readback"]
+ ) == strict
assert data["current_policy"]["low_risk_controlled_apply_allowed"] is True
assert data["current_policy"]["medium_risk_controlled_apply_allowed"] is True
assert data["current_policy"]["high_risk_controlled_apply_allowed"] is True
diff --git a/apps/api/tests/test_iwooos_security_asset_control_plane.py b/apps/api/tests/test_iwooos_security_asset_control_plane.py
index 9e724ed12..12fa999fa 100644
--- a/apps/api/tests/test_iwooos_security_asset_control_plane.py
+++ b/apps/api/tests/test_iwooos_security_asset_control_plane.py
@@ -3,6 +3,7 @@ from __future__ import annotations
# ruff: noqa: E402, I001
import asyncio
+import copy
import json
import os
from datetime import UTC, datetime, timedelta
@@ -20,12 +21,51 @@ from src.services.iwooos_security_asset_control_plane import (
build_iwooos_security_asset_control_plane,
build_unavailable_iwooos_security_asset_control_plane,
)
+from src.services.ai_automation_runtime_contract import (
+ AI_AUTOMATION_REQUIRED_LOOP_STAGES,
+ AI_AUTOMATION_RUNTIME_CONTRACT_SCHEMA_VERSION,
+)
def _row(**values):
return SimpleNamespace(**values)
+def _closed_strict_runtime() -> dict:
+ return {
+ "schema_version": "ai_agent_strict_runtime_completion_v2",
+ "runtime_contract_schema_version": (
+ AI_AUTOMATION_RUNTIME_CONTRACT_SCHEMA_VERSION
+ ),
+ "completion_percent": 100,
+ "required_stage_count": len(AI_AUTOMATION_REQUIRED_LOOP_STAGES),
+ "present_stage_count": len(AI_AUTOMATION_REQUIRED_LOOP_STAGES),
+ "missing_stage_ids": [],
+ "latest_flow_closed": True,
+ "latest_loop_closed": True,
+ "execution_loop_closed": True,
+ "same_run_correlation": True,
+ "full_trace_same_run_correlation_proven": True,
+ "automation_run_id": "internal-run-identity",
+ "run_id_mismatch_stage_ids": [],
+ "uncorrelated_stage_ids": [],
+ "stage_contracts": [
+ {
+ "stage_id": stage_id,
+ "evidence_present": True,
+ "same_run_correlation_proven": True,
+ "completion_eligible": True,
+ "evidence_source": "same_run_runtime_stage_receipt",
+ }
+ for stage_id in AI_AUTOMATION_REQUIRED_LOOP_STAGES
+ ],
+ "closed": True,
+ "same_run_correlation_required": True,
+ "metadata_only_counts_as_completion": False,
+ "historical_aggregate_fallback_allowed": False,
+ }
+
+
def _ready_payload(
source_health: list[dict] | None = None,
*,
@@ -33,6 +73,7 @@ def _ready_payload(
discovery_error: str | None = None,
automation_rows: list[SimpleNamespace] | None = None,
runtime_receipt_counts: dict[str, int] | None = None,
+ strict_runtime: dict | None = None,
) -> dict:
now = datetime(2026, 7, 11, 4, 0, tzinfo=UTC)
discovery = _row(
@@ -124,6 +165,7 @@ def _ready_payload(
learning_writeback_count_24h=runtime_counts.get("learn", 0),
mttr_minutes_24h=14.25,
),
+ strict_runtime_row=strict_runtime,
audit_row=_row(
k8s_audit_count_24h=2,
k8s_audit_failure_count_24h=0,
@@ -249,6 +291,92 @@ def test_projects_canonical_runtime_receipts_without_false_same_run_closure() ->
assert work_items["AIA-P0-008-01"]["gap_count"] == 1
+def test_projects_exact_authoritative_same_run_runtime_closure() -> None:
+ payload = _ready_payload(strict_runtime=_closed_strict_runtime())
+
+ strict = payload["ai_automation"]["strict_runtime_completion"]
+ assert strict == {
+ "schema_version": "ai_agent_strict_runtime_completion_v2",
+ "runtime_contract_schema_version": (
+ AI_AUTOMATION_RUNTIME_CONTRACT_SCHEMA_VERSION
+ ),
+ "contract_compatible": True,
+ "completion_percent": 100,
+ "required_stage_count": len(AI_AUTOMATION_REQUIRED_LOOP_STAGES),
+ "present_stage_count": len(AI_AUTOMATION_REQUIRED_LOOP_STAGES),
+ "missing_stage_count": 0,
+ "same_run_correlation": True,
+ "full_trace_same_run_correlation_proven": True,
+ "execution_loop_closed": True,
+ "closed": True,
+ "reason_code": None,
+ "cache_fallback_active": False,
+ "raw_run_identity_returned": False,
+ "raw_stage_receipts_returned": False,
+ }
+ assert payload["completion"]["strict_runtime_closure_percent"] == 100
+ assert payload["ai_automation"]["same_run_closed_loop_proven"] is True
+ assert payload["ai_automation"]["same_run_closed_loop_count"] == 1
+ assert all(
+ item["work_item_id"] != "AIA-P0-008-01"
+ for item in payload["work_items"]
+ )
+ assert payload["completion"]["overall_percent"] == round(
+ sum(
+ dimension["completion_percent"]
+ for dimension in payload["completion"]["dimensions"]
+ )
+ / payload["completion"]["dimension_count"]
+ )
+
+ public_text = json.dumps(payload, ensure_ascii=False)
+ assert "internal-run-identity" not in public_text
+ assert '"automation_run_id"' not in public_text
+ assert '"stage_contracts"' not in public_text
+
+
+def test_strict_runtime_projection_fails_closed_on_contract_or_receipt_drift() -> None:
+ variants: list[dict] = []
+
+ bad_schema = _closed_strict_runtime()
+ bad_schema["schema_version"] = "ai_agent_strict_runtime_completion_v1"
+ variants.append(bad_schema)
+
+ missing_stage = _closed_strict_runtime()
+ missing_stage["present_stage_count"] -= 1
+ missing_stage["missing_stage_ids"] = [AI_AUTOMATION_REQUIRED_LOOP_STAGES[-1]]
+ variants.append(missing_stage)
+
+ cross_run = _closed_strict_runtime()
+ cross_run["same_run_correlation"] = False
+ cross_run["run_id_mismatch_stage_ids"] = ["telegram_receipt"]
+ variants.append(cross_run)
+
+ no_run_identity = _closed_strict_runtime()
+ no_run_identity["automation_run_id"] = ""
+ variants.append(no_run_identity)
+
+ metadata_only = _closed_strict_runtime()
+ metadata_only["metadata_only_counts_as_completion"] = True
+ variants.append(metadata_only)
+
+ invalid_stage_contract = copy.deepcopy(_closed_strict_runtime())
+ invalid_stage_contract["stage_contracts"][0]["completion_eligible"] = False
+ variants.append(invalid_stage_contract)
+
+ for strict_runtime in variants:
+ payload = _ready_payload(strict_runtime=strict_runtime)
+ strict = payload["ai_automation"]["strict_runtime_completion"]
+ assert strict["closed"] is False
+ assert strict["completion_percent"] == 0
+ assert payload["completion"]["strict_runtime_closure_percent"] == 0
+ assert payload["ai_automation"]["same_run_closed_loop_proven"] is False
+ assert any(
+ item["work_item_id"] == "AIA-P0-008-01"
+ for item in payload["work_items"]
+ )
+
+
def test_discovery_failure_exposes_only_allowlisted_collector_ids() -> None:
raw_error = (
"RuntimeError: asset_collector_failures=domain_tls_inventory,"
@@ -612,6 +740,9 @@ def test_unavailable_payload_is_fixed_degraded_contract_without_raw_error() -> N
assert payload["summary"]["overall_security_completion_percent"] == 0
assert payload["completion"]["overall_percent"] == 0
assert payload["completion"]["strict_runtime_closure_percent"] == 0
+ assert payload["summary"]["source_count"] == 10
+ assert payload["summary"]["unavailable_source_count"] == 10
+ assert payload["ai_automation"]["strict_runtime_completion"]["closed"] is False
assert payload["discovery"]["fresh"] is False
assert payload["boundaries"]["raw_asset_identity_returned"] is False
assert payload["boundaries"]["raw_event_payload_returned"] is False
@@ -676,12 +807,25 @@ def test_service_uses_canonical_awoooi_project_scope(monkeypatch) -> None:
"src.services.iwooos_security_asset_control_plane.get_db_context",
fake_db_context,
)
+
+ async def strict_runtime_unavailable():
+ return {}, {
+ "source_id": "autonomous_strict_runtime",
+ "status": "unavailable",
+ "reason_code": "autonomous_strict_runtime_query_failed",
+ }
+
+ monkeypatch.setattr(
+ "src.services.iwooos_security_asset_control_plane._read_strict_runtime_source",
+ strict_runtime_unavailable,
+ )
payload = asyncio.run(service.get_snapshot())
assert requested_projects == ["awoooi"] * 9
assert payload["status"] == "degraded"
assert payload["source_status"] == "live_database_unavailable"
- assert payload["summary"]["unavailable_source_count"] == 9
+ assert payload["summary"]["source_count"] == 10
+ assert payload["summary"]["unavailable_source_count"] == 10
def test_service_bounds_source_concurrency_for_database_budget(monkeypatch) -> None:
@@ -719,11 +863,23 @@ def test_service_bounds_source_concurrency_for_database_budget(monkeypatch) -> N
"src.services.iwooos_security_asset_control_plane.get_db_context",
lambda project_id: DbContext(),
)
+
+ async def strict_runtime_ready():
+ return _closed_strict_runtime(), {
+ "source_id": "autonomous_strict_runtime",
+ "status": "ready",
+ "reason_code": None,
+ }
+
+ monkeypatch.setattr(
+ "src.services.iwooos_security_asset_control_plane._read_strict_runtime_source",
+ strict_runtime_ready,
+ )
payload = asyncio.run(service._load_snapshot())
assert concurrency["maximum"] == 3
- assert payload["summary"]["source_count"] == 9
- assert payload["summary"]["ready_source_count"] == 9
+ assert payload["summary"]["source_count"] == 10
+ assert payload["summary"]["ready_source_count"] == 10
assert payload["summary"]["unavailable_source_count"] == 0
compliance_query = next(
statement
diff --git a/apps/web/src/components/iwooos/security-asset-control-plane-cockpit.tsx b/apps/web/src/components/iwooos/security-asset-control-plane-cockpit.tsx
index b12c17689..07b5649e1 100644
--- a/apps/web/src/components/iwooos/security-asset-control-plane-cockpit.tsx
+++ b/apps/web/src/components/iwooos/security-asset-control-plane-cockpit.tsx
@@ -36,7 +36,7 @@ type Copy = {
assetTypes: string;
nist: string;
siem: string;
- aiLoop: string;
+ strictRun: string;
verified: string;
functions: string;
framework: string;
@@ -70,6 +70,7 @@ type Copy = {
failedCollectors: string;
failedCollectorsUnavailable: string;
sameRunMissing: string;
+ sameRunVerified: string;
loading: string;
unavailable: string;
refresh: string;
@@ -87,7 +88,7 @@ const COPY: Record<"zh" | "en", Copy> = {
assetTypes: "資產類型",
nist: "NIST 控制",
siem: "SIEM 閉環",
- aiLoop: "AI 閉環",
+ strictRun: "同 run 閉環",
verified: "24h 已驗證",
functions: "治理六功能",
framework: "完整資安框架",
@@ -121,6 +122,7 @@ const COPY: Record<"zh" | "en", Copy> = {
failedCollectors: "失敗 Collector",
failedCollectorsUnavailable: "失敗原因待安全分類",
sameRunMissing: "尚無同 run 閉環證據",
+ sameRunVerified: "18 段同 run 閉環已驗證",
loading: "正在載入資安控制平面",
unavailable: "Live readback 無法取得",
refresh: "重新整理資安控制平面",
@@ -136,7 +138,7 @@ const COPY: Record<"zh" | "en", Copy> = {
assetTypes: "Asset types",
nist: "NIST control",
siem: "SIEM closure",
- aiLoop: "AI closure",
+ strictRun: "Same-run closure",
verified: "Verified 24h",
functions: "Six functions",
framework: "Security framework",
@@ -170,6 +172,7 @@ const COPY: Record<"zh" | "en", Copy> = {
failedCollectors: "Failed collectors",
failedCollectorsUnavailable: "Failure detail awaiting safe classification",
sameRunMissing: "No same-run closure evidence",
+ sameRunVerified: "18-stage same-run closure verified",
loading: "Loading security control plane",
unavailable: "Live readback unavailable",
refresh: "Refresh security control plane",
@@ -557,10 +560,10 @@ export function SecurityAssetControlPlaneCockpit({
icon={Radar}
/>