fix: report current M4 M5 runtime blockers
This commit is contained in:
@@ -78,8 +78,8 @@ degraded/read-only mode, with `promotesM3M4M5=false`.
|
||||
| M1 | `LOCAL` | `docs/m1-local-smoke.md`, `fixtures/mvp/runtime.json`, `scripts/m1-contract-smoke.mjs`. |
|
||||
| M2 | `DEV-LIVE` for frontend/route only | DEV deploy smoke fixture plus active read-only `16666`/`16667` endpoint smoke and degraded/read-only frontend visibility. |
|
||||
| M3 | `BLOCKED` | Hardware trusted loop topology fixture, local patch-panel smoke, and the no-write DEV plan exist, but DEV-LIVE operation/trace/audit/evidence IDs for `res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1` are missing. |
|
||||
| M4 | `BLOCKED` | Agent automation loop fixture and local smoke exist, but live preflight is blocked at DB live readiness. |
|
||||
| M5 | `BLOCKED` | MVP e2e dry-run plan is green, but bounded DEV-LIVE acceptance is blocked by DB/M3/M4 and source/artifact coverage. |
|
||||
| M4 | `BLOCKED` | Agent automation loop fixture and local smoke exist, but live preflight is blocked at runtime durable adapter readiness and skills commit/version injection, not stale DB-live readiness. |
|
||||
| M5 | `BLOCKED` | MVP e2e dry-run plan is green, but bounded DEV-LIVE acceptance is blocked by runtime durable adapter, skills injection, M3/M4, and source/artifact coverage. |
|
||||
|
||||
`milestoneLevelClassification` is the compact M0-M5 answer for command
|
||||
handoff. `milestoneBlockerClassification` gives the M3/M4/M5 blocker class,
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@
|
||||
"reportVersion": "v1",
|
||||
"issue": "pikasTech/HWLAB#37",
|
||||
"taskId": "dev-m4-agent-loop",
|
||||
"commitId": "0614202",
|
||||
"commitId": "d881a50",
|
||||
"acceptanceLevel": "dev_m4_agent_loop",
|
||||
"devOnly": true,
|
||||
"prodDisabled": true,
|
||||
@@ -94,21 +94,26 @@
|
||||
"summary": "Dry-run produced trace/evidence records and removed the temporary worker workspace."
|
||||
},
|
||||
"dbLive": {
|
||||
"level": "BLOCKED",
|
||||
"status": "blocked",
|
||||
"summary": "Live scheduling is stopped at cloud-api DB readiness; DB health is classified separately from local dry-run evidence."
|
||||
"level": "DEV-LIVE",
|
||||
"status": "pass",
|
||||
"summary": "Current read-only /health/live evidence reports DB ready=true, connected=true, and liveDbEvidence=true; DB live is no longer the active M4 blocker."
|
||||
},
|
||||
"m3HardwareLoopDependency": {
|
||||
"level": "BLOCKED",
|
||||
"status": "not_run",
|
||||
"requiredPath": "DO1 -> hwlab-patch-panel -> DI1",
|
||||
"summary": "M4 can only support M3 through cloud-api/hardware API and the patch-panel trusted path; no direct box/gateway path is used."
|
||||
},
|
||||
"runtimeDurableAdapter": {
|
||||
"level": "BLOCKED",
|
||||
"status": "blocked",
|
||||
"summary": "Live scheduling is stopped at runtime durable adapter readiness; DB live evidence alone is not runtime durability evidence."
|
||||
}
|
||||
},
|
||||
"dependencyState": {
|
||||
"dbLive": {
|
||||
"status": "blocked",
|
||||
"summary": "cloud-api /health/live reports DB degraded; connected=false; ready=false."
|
||||
"status": "pass",
|
||||
"summary": "cloud-api /health/live reports DB ready=true, connected=true, and liveDbEvidence=true."
|
||||
},
|
||||
"m3HardwareLoop": {
|
||||
"status": "not_run",
|
||||
@@ -123,6 +128,11 @@
|
||||
"direct hwlab-gateway-simu access",
|
||||
"agent-side fixture promotion to DEV-LIVE"
|
||||
]
|
||||
},
|
||||
"runtimeDurableAdapter": {
|
||||
"status": "blocked",
|
||||
"requiredEvidence": "Postgres runtime adapter schema, migration ledger, and read-query readiness with liveRuntimeEvidence=true.",
|
||||
"summary": "cloud-api durable runtime adapter is blocked: runtime_durable_adapter_query_blocked; migration 0001_cloud_core_skeleton is missing or not checked; read-query durability is not proven."
|
||||
}
|
||||
},
|
||||
"d601K3sNative": {
|
||||
@@ -168,7 +178,7 @@
|
||||
"agentManager": {
|
||||
"deployment": {
|
||||
"name": "hwlab-agent-mgr",
|
||||
"image": "127.0.0.1:5000/hwlab/hwlab-agent-mgr:cb35ada",
|
||||
"image": "127.0.0.1:5000/hwlab/hwlab-agent-mgr:d881a50",
|
||||
"readyReplicas": 1,
|
||||
"replicas": 1,
|
||||
"available": "True",
|
||||
@@ -195,14 +205,14 @@
|
||||
"agentSkills": {
|
||||
"deployment": {
|
||||
"name": "hwlab-agent-skills",
|
||||
"image": "127.0.0.1:5000/hwlab/hwlab-agent-skills:cb35ada",
|
||||
"image": "127.0.0.1:5000/hwlab/hwlab-agent-skills:d881a50",
|
||||
"readyReplicas": 1,
|
||||
"replicas": 1,
|
||||
"available": "True",
|
||||
"ready": true,
|
||||
"env": {
|
||||
"values": {
|
||||
"HWLAB_SKILLS_COMMIT_ID": "cb35ada"
|
||||
"HWLAB_SKILLS_COMMIT_ID": "d881a50"
|
||||
},
|
||||
"valueFrom": []
|
||||
}
|
||||
@@ -212,7 +222,7 @@
|
||||
"statusCode": 200,
|
||||
"status": "ok",
|
||||
"serviceId": "hwlab-agent-skills",
|
||||
"revision": "cb35ada6860653b27269b0a57991184118cbf4b1",
|
||||
"revision": "d881a50",
|
||||
"error": null
|
||||
}
|
||||
},
|
||||
@@ -220,7 +230,7 @@
|
||||
"template": {
|
||||
"name": "hwlab-agent-worker-template",
|
||||
"suspend": true,
|
||||
"image": "127.0.0.1:5000/hwlab/hwlab-agent-worker:cb35ada",
|
||||
"image": "127.0.0.1:5000/hwlab/hwlab-agent-worker:d881a50",
|
||||
"restartPolicy": "Never",
|
||||
"env": {
|
||||
"values": {
|
||||
@@ -251,9 +261,9 @@
|
||||
"skillsInjection": {
|
||||
"status": "blocked",
|
||||
"source": "k3s deployment env plus generated worker dry-run manifest",
|
||||
"serviceCommitId": "cb35ada",
|
||||
"serviceCommitId": "d881a50",
|
||||
"serviceVersion": null,
|
||||
"workerDryRunCommitId": "cb35ada",
|
||||
"workerDryRunCommitId": "d881a50",
|
||||
"workerDryRunVersion": "",
|
||||
"workerDryRunSource": "derived-from-live-dev-skills-env",
|
||||
"missing": [
|
||||
@@ -271,11 +281,11 @@
|
||||
"k3s:deploy/hwlab-agent-skills:ready=1/1:available=True",
|
||||
"k3s:svc/hwlab-agent-mgr:endpoints=1",
|
||||
"k3s:svc/hwlab-agent-skills:endpoints=1",
|
||||
"agent-mgr:/health/live:degraded",
|
||||
"agent-skills:/health/live:ok:cb35ada6860653b27269b0a57991184118cbf4b1",
|
||||
"worker-template:suspend=true:image=127.0.0.1:5000/hwlab/hwlab-agent-worker:cb35ada",
|
||||
"agent-mgr:/health/live:degraded:missing=manager.skillCommitId,manager.skillVersion",
|
||||
"agent-skills:/health/live:ok:d881a50",
|
||||
"worker-template:suspend=true:image=127.0.0.1:5000/hwlab/hwlab-agent-worker:d881a50",
|
||||
"worker-job:server-dry-run=true:persisted=false",
|
||||
"skills-injection:commit=cb35ada:version=missing",
|
||||
"skills-injection:commit=d881a50:version=missing",
|
||||
"secret-rbac:get=yes:secretResourcesRead=false"
|
||||
],
|
||||
"blockers": [
|
||||
@@ -323,12 +333,168 @@
|
||||
"environment": "dev",
|
||||
"status": "degraded",
|
||||
"db": {
|
||||
"status": "degraded",
|
||||
"connected": false,
|
||||
"ready": false,
|
||||
"evidence": "env_presence_only_no_live_db"
|
||||
"status": "ok",
|
||||
"connected": true,
|
||||
"liveConnected": true,
|
||||
"ready": true,
|
||||
"configReady": true,
|
||||
"connectionChecked": true,
|
||||
"connectionAttempted": true,
|
||||
"connectionResult": "connected",
|
||||
"endpointSource": "secret-url-host",
|
||||
"liveDbEvidence": true,
|
||||
"evidence": "live_db_tcp_connection_ready"
|
||||
},
|
||||
"error": null
|
||||
"error": null,
|
||||
"codeAgent": {
|
||||
"endpoint": "POST /v1/agent/chat",
|
||||
"status": "available",
|
||||
"ready": true,
|
||||
"provider": "openai-responses",
|
||||
"schema": [
|
||||
"conversationId",
|
||||
"sessionId",
|
||||
"messageId",
|
||||
"status",
|
||||
"createdAt",
|
||||
"updatedAt",
|
||||
"traceId",
|
||||
"provider",
|
||||
"model",
|
||||
"backend",
|
||||
"error.message"
|
||||
]
|
||||
},
|
||||
"runtime": {
|
||||
"adapter": "postgres",
|
||||
"durable": false,
|
||||
"durableRequested": true,
|
||||
"durableCapable": false,
|
||||
"ready": false,
|
||||
"status": "blocked",
|
||||
"blocker": "runtime_durable_adapter_query_blocked",
|
||||
"reason": "Postgres runtime adapter is configured, but durable read-query readiness is blocked; migration 0001_cloud_core_skeleton is missing or not checked.",
|
||||
"liveRuntimeEvidence": false,
|
||||
"fixtureEvidence": false,
|
||||
"connection": {
|
||||
"queryAttempted": true,
|
||||
"queryResult": "query_blocked",
|
||||
"endpointRedacted": true,
|
||||
"valueRedacted": true,
|
||||
"errorCode": "not_observed"
|
||||
},
|
||||
"schema": {
|
||||
"checked": true,
|
||||
"ready": true,
|
||||
"missingTables": [],
|
||||
"missingColumns": []
|
||||
},
|
||||
"migration": {
|
||||
"checked": false,
|
||||
"ready": false,
|
||||
"missing": true,
|
||||
"requiredMigrationId": "0001_cloud_core_skeleton",
|
||||
"requiredSchemaVersion": "runtime-durable-postgres-v1",
|
||||
"appliedMigrationId": null,
|
||||
"appliedSchemaVersion": null
|
||||
},
|
||||
"gates": {
|
||||
"auth": {
|
||||
"checked": true,
|
||||
"ready": true,
|
||||
"status": "ready",
|
||||
"blocker": null
|
||||
},
|
||||
"schema": {
|
||||
"checked": true,
|
||||
"ready": true,
|
||||
"status": "ready",
|
||||
"blocker": null
|
||||
},
|
||||
"migration": {
|
||||
"checked": false,
|
||||
"ready": false,
|
||||
"status": "blocked",
|
||||
"blocker": "runtime_durable_adapter_migration_blocked"
|
||||
},
|
||||
"durability": {
|
||||
"checked": true,
|
||||
"ready": false,
|
||||
"status": "blocked",
|
||||
"blocker": "runtime_durable_adapter_query_blocked"
|
||||
}
|
||||
},
|
||||
"durabilityContract": {
|
||||
"ready": false,
|
||||
"status": "blocked",
|
||||
"blockedLayer": "durability_query",
|
||||
"requiredEvidence": "runtime_adapter_schema_migration_read_query",
|
||||
"dbLiveEvidenceIsDurabilityEvidence": false,
|
||||
"secretMaterialRead": false
|
||||
},
|
||||
"counts": {}
|
||||
},
|
||||
"readiness": {
|
||||
"contractVersion": "v3",
|
||||
"ready": false,
|
||||
"status": "degraded",
|
||||
"blockerCodes": [
|
||||
"runtime_durable_adapter_query_blocked"
|
||||
],
|
||||
"components": {
|
||||
"db": "ready",
|
||||
"codeAgent": "ready",
|
||||
"runtime": "blocked"
|
||||
},
|
||||
"durability": {
|
||||
"status": "blocked",
|
||||
"ready": false,
|
||||
"adapter": "postgres",
|
||||
"durable": false,
|
||||
"durableRequested": true,
|
||||
"durableCapable": false,
|
||||
"runtimeStatus": "blocked",
|
||||
"runtimeReady": false,
|
||||
"liveRuntimeEvidence": false,
|
||||
"dbLiveEvidenceObserved": true,
|
||||
"dbLiveEvidenceIsDurabilityEvidence": false,
|
||||
"requiredEvidence": "runtime_adapter_schema_migration_read_query",
|
||||
"blockedLayer": "durability_query",
|
||||
"blocker": "runtime_durable_adapter_query_blocked",
|
||||
"gates": {
|
||||
"auth": {
|
||||
"checked": true,
|
||||
"ready": true,
|
||||
"status": "ready",
|
||||
"blocker": null
|
||||
},
|
||||
"schema": {
|
||||
"checked": true,
|
||||
"ready": true,
|
||||
"status": "ready",
|
||||
"blocker": null
|
||||
},
|
||||
"migration": {
|
||||
"checked": false,
|
||||
"ready": false,
|
||||
"status": "blocked",
|
||||
"blocker": "runtime_durable_adapter_migration_blocked"
|
||||
},
|
||||
"durability": {
|
||||
"checked": true,
|
||||
"ready": false,
|
||||
"status": "blocked",
|
||||
"blocker": "runtime_durable_adapter_query_blocked"
|
||||
}
|
||||
},
|
||||
"queryAttempted": true,
|
||||
"queryResult": "query_blocked",
|
||||
"secretMaterialRead": false
|
||||
}
|
||||
},
|
||||
"blockerCodes": [
|
||||
"runtime_durable_adapter_query_blocked"
|
||||
]
|
||||
}
|
||||
},
|
||||
"frontend": {
|
||||
@@ -338,7 +504,7 @@
|
||||
"contentLength": "11180",
|
||||
"error": null
|
||||
},
|
||||
"summary": "Public DEV API http://74.48.78.17:16667 health=200 live=200; frontend http://74.48.78.17:16666/=200."
|
||||
"summary": "Public DEV API http://74.48.78.17:16667 health=200 live=200 with DB live ready and runtime durable adapter blocked; frontend http://74.48.78.17:16666/=200."
|
||||
},
|
||||
"safetyEvidence": {
|
||||
"devOnly": true,
|
||||
@@ -359,24 +525,26 @@
|
||||
},
|
||||
"devPreconditions": {
|
||||
"status": "blocked",
|
||||
"classification": "DB live",
|
||||
"classification": "runtime_durable_adapter_query_blocked",
|
||||
"requirements": [
|
||||
"DEV route remains frozen at http://74.48.78.17:16667",
|
||||
"DEV browser route remains frozen at http://74.48.78.17:16666",
|
||||
"D601 native k3s access uses KUBECONFIG=/etc/rancher/k3s/k3s.yaml and namespace hwlab-dev",
|
||||
"No secret reads, real deployment, or long-running agent task is attempted",
|
||||
"DB live readiness and runtime durable adapter readiness are separate gates; DB live alone cannot promote M4",
|
||||
"Agent manager, worker, and skills are reachable only through the cloud API boundary",
|
||||
"M4 hardware assistance must go through cloud-api/hardware API and patch-panel; direct box/gateway access is forbidden"
|
||||
],
|
||||
"summary": "Blocked at DB live readiness before scheduling a DEV agent task."
|
||||
"summary": "Blocked at runtime durable adapter readiness before scheduling a DEV agent task."
|
||||
},
|
||||
"blockers": [
|
||||
{
|
||||
"type": "runtime_blocker",
|
||||
"scope": "db-live",
|
||||
"scope": "runtime-durable-adapter",
|
||||
"status": "open",
|
||||
"summary": "cloud-api /health/live reports DB degraded; connected=false; ready=false.",
|
||||
"classification": "DB live"
|
||||
"sourceIssue": "pikasTech/HWLAB#164",
|
||||
"summary": "cloud-api durable runtime adapter is blocked: runtime_durable_adapter_query_blocked; adapter=postgres; durable=false; ready=false; migration=0001_cloud_core_skeleton checked=false ready=false missing=true; queryResult=query_blocked.",
|
||||
"classification": "runtime_durable_adapter_query_blocked"
|
||||
},
|
||||
{
|
||||
"status": "open",
|
||||
@@ -397,7 +565,7 @@
|
||||
],
|
||||
"livePreflight": {
|
||||
"status": "blocked",
|
||||
"classification": "DB live",
|
||||
"classification": "runtime_durable_adapter_query_blocked",
|
||||
"commands": [
|
||||
"node scripts/dev-m4-agent-loop-smoke.mjs --live --confirm-dev --confirmed-non-production"
|
||||
],
|
||||
@@ -407,17 +575,19 @@
|
||||
"k3s:deploy/hwlab-agent-skills:ready=1/1:available=True",
|
||||
"k3s:svc/hwlab-agent-mgr:endpoints=1",
|
||||
"k3s:svc/hwlab-agent-skills:endpoints=1",
|
||||
"agent-mgr:/health/live:degraded",
|
||||
"agent-skills:/health/live:ok:cb35ada6860653b27269b0a57991184118cbf4b1",
|
||||
"worker-template:suspend=true:image=127.0.0.1:5000/hwlab/hwlab-agent-worker:cb35ada",
|
||||
"agent-mgr:/health/live:degraded:missing=manager.skillCommitId,manager.skillVersion",
|
||||
"agent-skills:/health/live:ok:d881a50",
|
||||
"worker-template:suspend=true:image=127.0.0.1:5000/hwlab/hwlab-agent-worker:d881a50",
|
||||
"worker-job:server-dry-run=true:persisted=false",
|
||||
"skills-injection:commit=cb35ada:version=missing",
|
||||
"skills-injection:commit=d881a50:version=missing",
|
||||
"secret-rbac:get=yes:secretResourcesRead=false",
|
||||
"Public DEV API http://74.48.78.17:16667 health=200 live=200; frontend http://74.48.78.17:16666/=200.",
|
||||
"Public DEV API http://74.48.78.17:16667 health=200 live=200 with DB live ready and runtime durable adapter blocked; frontend http://74.48.78.17:16666/=200.",
|
||||
"health:hwlab-edge-proxy:dev:ok",
|
||||
"live:hwlab-cloud-api:degraded:db-blocked"
|
||||
"live:hwlab-cloud-api:degraded:runtime-durable-adapter-blocked:runtime_durable_adapter_query_blocked",
|
||||
"db-live:ready=true:connected=true:liveDbEvidence=true",
|
||||
"runtime-durable-adapter:adapter=postgres:blocker=runtime_durable_adapter_query_blocked:migration=0001_cloud_core_skeleton:migrationChecked=false:migrationReady=false:queryResult=query_blocked"
|
||||
],
|
||||
"summary": "Blocked at DB live readiness before scheduling a DEV agent task."
|
||||
"summary": "Blocked at runtime durable adapter readiness before scheduling a DEV agent task."
|
||||
},
|
||||
"notes": "DEV M4 agent loop report. SOURCE/LOCAL/DRY-RUN evidence is not DEV-LIVE, and no secret material is read."
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
"pikasTech/HWLAB#46",
|
||||
"pikasTech/HWLAB#64"
|
||||
],
|
||||
"generatedAt": "2026-05-23T03:16:52.953Z",
|
||||
"generatedFromCommit": "96e802b2a22c",
|
||||
"generatedAt": "2026-05-23T06:17:15.938Z",
|
||||
"generatedFromCommit": "66586ccf109e",
|
||||
"environment": "dev",
|
||||
"endpoint": "http://74.48.78.17:16667",
|
||||
"frontendEndpoint": "http://74.48.78.17:16666",
|
||||
@@ -116,7 +116,7 @@
|
||||
"taskId": "dev-m4-agent-loop",
|
||||
"lifecycleState": "active",
|
||||
"status": "blocked",
|
||||
"commitId": "0614202"
|
||||
"commitId": "d881a50"
|
||||
},
|
||||
"devM5Gate": {
|
||||
"path": "reports/dev-gate/dev-mvp-gate-report.json",
|
||||
@@ -138,7 +138,7 @@
|
||||
"overall": {
|
||||
"status": "blocked",
|
||||
"green": false,
|
||||
"reason": "Frontend revision 1e8805664970839b72be40c34636b08f6d18b131 is usable in degraded/read-only mode and EDGE/ROUTE DEV-LIVE evidence exists on :16666/:16667, but M5 remains blocked by artifact source drift, API/runtime durability degradation, missing M3 trusted loop operation evidence, and blocked M4 agent-loop preflight."
|
||||
"reason": "Frontend revision 1e8805664970839b72be40c34636b08f6d18b131 is usable in degraded/read-only mode and EDGE/ROUTE DEV-LIVE evidence exists on :16666/:16667, but M5 remains blocked by artifact source drift, runtime durable adapter or skills injection readiness, missing M3 trusted loop operation evidence, and blocked M4 agent-loop preflight."
|
||||
},
|
||||
"latestFrontendDevFact": {
|
||||
"revision": "1e8805664970839b72be40c34636b08f6d18b131",
|
||||
@@ -204,9 +204,9 @@
|
||||
},
|
||||
{
|
||||
"id": "cloud-api-db-ready",
|
||||
"status": "blocked",
|
||||
"evidenceLevel": "BLOCKED",
|
||||
"summary": "cloud-api DB status=degraded; ready=false; connected=false; endpointSource=unknown; liveDbEvidence=false."
|
||||
"status": "pass",
|
||||
"evidenceLevel": "DEV-LIVE",
|
||||
"summary": "cloud-api DB status=ok; ready=true; connected=true; endpointSource=secret-url-host; liveDbEvidence=true."
|
||||
},
|
||||
{
|
||||
"id": "m3-hardware-trusted-loop",
|
||||
@@ -255,16 +255,53 @@
|
||||
},
|
||||
"dbLive": {
|
||||
"label": "DB live/degraded",
|
||||
"status": "blocked",
|
||||
"evidenceLevel": "BLOCKED",
|
||||
"summary": "cloud-api DB status=degraded; configReady=true; ready=false; connected=false; endpointSource=unknown; liveDbEvidence=false.",
|
||||
"status": "pass",
|
||||
"evidenceLevel": "DEV-LIVE",
|
||||
"summary": "cloud-api DB status=ok; configReady=true; ready=true; connected=true; endpointSource=secret-url-host; liveDbEvidence=true.",
|
||||
"evidence": [
|
||||
"http://74.48.78.17:16667/health/live -> HTTP 200 serviceId=hwlab-cloud-api status=degraded db.ready=false db.connected=false db.connectionChecked=false",
|
||||
"dev-edge-health active report -> blocked by DB live readiness, while public 16667 TCP/HTTP and frp control/tunnel health are reachable",
|
||||
"dev-m4-agent-loop active report -> blocked, classification=DB live, summary=cloud-api /health/live reports DB degraded; connected=false; ready=false"
|
||||
"http://74.48.78.17:16667/health/live -> HTTP 200 serviceId=hwlab-cloud-api status=degraded db.ready=true db.connected=true db.liveDbEvidence=true runtime.blocker=runtime_durable_adapter_query_blocked runtime.migration=0001_cloud_core_skeleton",
|
||||
"dev-edge-health active report remains older DB-live evidence and is superseded for M4/M5 blocker naming by current d881a50 M4 preflight evidence"
|
||||
],
|
||||
"nextRequired": "Provide live DB connection evidence through redacted health output; route reachability alone is insufficient."
|
||||
},
|
||||
"runtimeDurableAdapter": {
|
||||
"label": "Runtime durable adapter",
|
||||
"status": "blocked",
|
||||
"evidenceLevel": "BLOCKED",
|
||||
"summary": "runtime adapter=postgres; durableRequested=true; durable=false; ready=false; blocker=runtime_durable_adapter_query_blocked; migration=0001_cloud_core_skeleton checked=false ready=false; queryResult=query_blocked.",
|
||||
"evidence": [
|
||||
"requiredEvidence=runtime_adapter_schema_migration_read_query",
|
||||
"blockedLayer=durability_query",
|
||||
"migration=0001_cloud_core_skeleton",
|
||||
"queryAttempted=true"
|
||||
],
|
||||
"nextRequired": "Repair the postgres durable runtime adapter query/migration readiness and rerun health/M4 preflight without treating DB live as durability proof."
|
||||
},
|
||||
"agentSkillsInjection": {
|
||||
"label": "Agent skills injection",
|
||||
"status": "blocked",
|
||||
"evidenceLevel": "BLOCKED",
|
||||
"summary": "DEV skills injection is incomplete: missing hwlab-agent-skills.HWLAB_SKILLS_VERSION, worker-dry-run.HWLAB_SKILL_VERSION_FROM_DEV.",
|
||||
"evidence": [
|
||||
"skills.commit=d881a50",
|
||||
"skills.version=missing",
|
||||
"worker.commit=d881a50",
|
||||
"worker.version=",
|
||||
"missing=hwlab-agent-skills.HWLAB_SKILLS_VERSION,worker-dry-run.HWLAB_SKILL_VERSION_FROM_DEV,manager.skillCommitId,manager.skillVersion"
|
||||
],
|
||||
"nextRequired": "Inject explicit skill commit and version into hwlab-agent-mgr, hwlab-agent-skills, and scheduled worker jobs before claiming M4/M5 agent evidence."
|
||||
},
|
||||
"codeAgentProvider": {
|
||||
"label": "Code Agent provider",
|
||||
"status": "pass",
|
||||
"evidenceLevel": "DEV-LIVE",
|
||||
"summary": "code-agent provider=openai-responses; status=available; ready=true.",
|
||||
"evidence": [
|
||||
"provider=openai-responses",
|
||||
"status=available"
|
||||
],
|
||||
"nextRequired": "Keep provider-backed Code Agent readiness separate from DB live and runtime durable adapter readiness."
|
||||
},
|
||||
"d601RunnerObservability": {
|
||||
"label": "D601 runner observability",
|
||||
"status": "blocked",
|
||||
@@ -296,24 +333,26 @@
|
||||
"label": "M4 agent loop",
|
||||
"status": "blocked",
|
||||
"evidenceLevel": "BLOCKED",
|
||||
"summary": "Blocked at DB live readiness before scheduling a DEV agent task.",
|
||||
"summary": "Blocked at runtime durable adapter readiness before scheduling a DEV agent task.",
|
||||
"evidence": [
|
||||
"k3s:namespace=hwlab-dev:read=true",
|
||||
"k3s:deploy/hwlab-agent-mgr:ready=1/1:available=True",
|
||||
"k3s:deploy/hwlab-agent-skills:ready=1/1:available=True",
|
||||
"k3s:svc/hwlab-agent-mgr:endpoints=1",
|
||||
"k3s:svc/hwlab-agent-skills:endpoints=1",
|
||||
"agent-mgr:/health/live:degraded",
|
||||
"agent-skills:/health/live:ok:cb35ada6860653b27269b0a57991184118cbf4b1",
|
||||
"worker-template:suspend=true:image=127.0.0.1:5000/hwlab/hwlab-agent-worker:cb35ada",
|
||||
"agent-mgr:/health/live:degraded:missing=manager.skillCommitId,manager.skillVersion",
|
||||
"agent-skills:/health/live:ok:d881a50",
|
||||
"worker-template:suspend=true:image=127.0.0.1:5000/hwlab/hwlab-agent-worker:d881a50",
|
||||
"worker-job:server-dry-run=true:persisted=false",
|
||||
"skills-injection:commit=cb35ada:version=missing",
|
||||
"skills-injection:commit=d881a50:version=missing",
|
||||
"secret-rbac:get=yes:secretResourcesRead=false",
|
||||
"Public DEV API http://74.48.78.17:16667 health=200 live=200; frontend http://74.48.78.17:16666/=200.",
|
||||
"Public DEV API http://74.48.78.17:16667 health=200 live=200 with DB live ready and runtime durable adapter blocked; frontend http://74.48.78.17:16666/=200.",
|
||||
"health:hwlab-edge-proxy:dev:ok",
|
||||
"live:hwlab-cloud-api:degraded:db-blocked"
|
||||
"live:hwlab-cloud-api:degraded:runtime-durable-adapter-blocked:runtime_durable_adapter_query_blocked",
|
||||
"db-live:ready=true:connected=true:liveDbEvidence=true",
|
||||
"runtime-durable-adapter:adapter=postgres:blocker=runtime_durable_adapter_query_blocked:migration=0001_cloud_core_skeleton:migrationChecked=false:migrationReady=false:queryResult=query_blocked"
|
||||
],
|
||||
"nextRequired": "Do not schedule or claim the agent loop as live until DB live and required runtime/evidence preconditions pass."
|
||||
"nextRequired": "Do not schedule or claim the agent loop as live until DB live, runtime durable adapter, skills injection, and required evidence preconditions pass."
|
||||
},
|
||||
"artifactDesiredStateSource": {
|
||||
"label": "artifact/desired-state source",
|
||||
@@ -367,7 +406,7 @@
|
||||
"status": "blocked",
|
||||
"strongestEvidenceLevel": "DRY-RUN",
|
||||
"liveEvidence": "missing_or_blocked",
|
||||
"summary": "DEV-LIVE agent loop is blocked at DB live readiness; local smoke is not acceptance."
|
||||
"summary": "DEV-LIVE agent loop is blocked at runtime durable adapter or skills injection readiness; local smoke is not acceptance."
|
||||
},
|
||||
{
|
||||
"milestone": "M5",
|
||||
@@ -404,31 +443,39 @@
|
||||
"milestone": "M4",
|
||||
"status": "blocked",
|
||||
"currentLevel": "BLOCKED",
|
||||
"blockerClass": "db-live-readiness",
|
||||
"dependency": "Cloud API /health/live must report DB ready=true, connected=true, endpointSource=secret-url-host, and liveDbEvidence=true before live agent scheduling/evidence closure.",
|
||||
"blockerClass": "runtime_durable_adapter_query_blocked",
|
||||
"dependency": "Cloud API /health/live must prove the postgres durable runtime adapter schema, 0001_cloud_core_skeleton migration ledger, and read-query readiness before live agent scheduling/evidence closure.",
|
||||
"evidence": [
|
||||
"db.status=degraded",
|
||||
"db.ready=false",
|
||||
"db.connected=false",
|
||||
"db.endpointSource=unknown",
|
||||
"db.liveDbEvidence=false"
|
||||
"db.status=ok",
|
||||
"db.ready=true",
|
||||
"db.connected=true",
|
||||
"db.endpointSource=secret-url-host",
|
||||
"db.liveDbEvidence=true",
|
||||
"runtime.adapter=postgres",
|
||||
"runtime.blocker=runtime_durable_adapter_query_blocked",
|
||||
"runtime.migration=0001_cloud_core_skeleton",
|
||||
"runtime.migration.ready=false",
|
||||
"runtime.queryResult=query_blocked",
|
||||
"skills.missing=hwlab-agent-skills.HWLAB_SKILLS_VERSION,worker-dry-run.HWLAB_SKILL_VERSION_FROM_DEV,manager.skillCommitId,manager.skillVersion"
|
||||
],
|
||||
"nextRequired": "Repair DB live readiness and rerun the M4 live preflight without scheduling a DEV agent task before preconditions pass.",
|
||||
"nonPromotionReason": "Frontend revision and read-only route reachability do not prove DB-backed agent runtime readiness."
|
||||
"nextRequired": "Repair the runtime durable adapter query/migration readiness and rerun the M4 live preflight without scheduling a DEV agent task before preconditions pass.",
|
||||
"nonPromotionReason": "Frontend revision and read-only route reachability do not prove DB-backed durable agent runtime readiness or skill version injection."
|
||||
},
|
||||
{
|
||||
"milestone": "M5",
|
||||
"status": "blocked",
|
||||
"currentLevel": "BLOCKED",
|
||||
"blockerClass": "composite-db-m3-m4-live",
|
||||
"dependency": "M5 needs DB live readiness, M3 trusted-loop DEV evidence, M4 live preflight/evidence closure, and current source/artifact coverage.",
|
||||
"blockerClass": "composite-runtime-durable-m3-m4-live",
|
||||
"dependency": "M5 needs DB live readiness, runtime durable adapter readiness, skills commit/version injection, M3 trusted-loop DEV evidence, M4 live preflight/evidence closure, and current source/artifact coverage.",
|
||||
"evidence": [
|
||||
"M5 dry-run is green",
|
||||
"db.ready=false",
|
||||
"db.ready=true",
|
||||
"runtime.blocker=runtime_durable_adapter_query_blocked",
|
||||
"skills.status=blocked",
|
||||
"m3.live=false",
|
||||
"m4.live=false"
|
||||
],
|
||||
"nextRequired": "After DB/M3/M4 blockers are cleared, run only the bounded DEV MVP live gate command with explicit DEV/non-PROD confirmations.",
|
||||
"nextRequired": "After DB/runtime durable adapter/skills/M3/M4 blockers are cleared, run only the bounded DEV MVP live gate command with explicit DEV/non-PROD confirmations.",
|
||||
"nonPromotionReason": "No frontend, route-only, local, or dry-run evidence is allowed to stand in for bounded DEV-LIVE MVP e2e acceptance."
|
||||
}
|
||||
],
|
||||
@@ -457,7 +504,7 @@
|
||||
"highestVisibleLevel": "DEV-LIVE",
|
||||
"liveEvidence": "pass",
|
||||
"evidenceCount": 7,
|
||||
"blockerCount": 7,
|
||||
"blockerCount": 4,
|
||||
"summary": "deploy/runtime readiness is blocked before live DEV; highest visible level is DEV-LIVE; status is blocked."
|
||||
},
|
||||
{
|
||||
@@ -475,7 +522,7 @@
|
||||
"highestVisibleLevel": "DRY-RUN",
|
||||
"liveEvidence": "missing_or_blocked",
|
||||
"evidenceCount": 3,
|
||||
"blockerCount": 2,
|
||||
"blockerCount": 3,
|
||||
"summary": "agent loop has local smoke but live preflight is blocked; highest visible level is DRY-RUN; status is blocked."
|
||||
},
|
||||
{
|
||||
@@ -484,7 +531,7 @@
|
||||
"highestVisibleLevel": "DRY-RUN",
|
||||
"liveEvidence": "missing_or_blocked",
|
||||
"evidenceCount": 2,
|
||||
"blockerCount": 16,
|
||||
"blockerCount": 11,
|
||||
"summary": "dry-run is green but live MVP gate is blocked; highest visible level is DRY-RUN; status is blocked."
|
||||
}
|
||||
],
|
||||
@@ -768,7 +815,7 @@
|
||||
"issue": "pikasTech/HWLAB#37",
|
||||
"taskId": "dev-m4-agent-loop",
|
||||
"reportPath": "reports/dev-gate/dev-m4-agent-loop.json",
|
||||
"commitId": "0614202",
|
||||
"commitId": "d881a50",
|
||||
"lifecycleState": "active",
|
||||
"level": "LOCAL",
|
||||
"status": "pass",
|
||||
@@ -787,7 +834,7 @@
|
||||
"issue": "pikasTech/HWLAB#37",
|
||||
"taskId": "dev-m4-agent-loop",
|
||||
"reportPath": "reports/dev-gate/dev-m4-agent-loop.json",
|
||||
"commitId": "0614202",
|
||||
"commitId": "d881a50",
|
||||
"lifecycleState": "active",
|
||||
"level": "DRY-RUN",
|
||||
"status": "pass",
|
||||
@@ -811,7 +858,7 @@
|
||||
"issue": "pikasTech/HWLAB#37",
|
||||
"taskId": "dev-m4-agent-loop",
|
||||
"reportPath": "reports/dev-gate/dev-m4-agent-loop.json",
|
||||
"commitId": "0614202",
|
||||
"commitId": "d881a50",
|
||||
"lifecycleState": "active",
|
||||
"level": "BLOCKED",
|
||||
"status": "blocked",
|
||||
@@ -825,17 +872,19 @@
|
||||
"k3s:deploy/hwlab-agent-skills:ready=1/1:available=True",
|
||||
"k3s:svc/hwlab-agent-mgr:endpoints=1",
|
||||
"k3s:svc/hwlab-agent-skills:endpoints=1",
|
||||
"agent-mgr:/health/live:degraded",
|
||||
"agent-skills:/health/live:ok:cb35ada6860653b27269b0a57991184118cbf4b1",
|
||||
"worker-template:suspend=true:image=127.0.0.1:5000/hwlab/hwlab-agent-worker:cb35ada",
|
||||
"agent-mgr:/health/live:degraded:missing=manager.skillCommitId,manager.skillVersion",
|
||||
"agent-skills:/health/live:ok:d881a50",
|
||||
"worker-template:suspend=true:image=127.0.0.1:5000/hwlab/hwlab-agent-worker:d881a50",
|
||||
"worker-job:server-dry-run=true:persisted=false",
|
||||
"skills-injection:commit=cb35ada:version=missing",
|
||||
"skills-injection:commit=d881a50:version=missing",
|
||||
"secret-rbac:get=yes:secretResourcesRead=false",
|
||||
"Public DEV API http://74.48.78.17:16667 health=200 live=200; frontend http://74.48.78.17:16666/=200.",
|
||||
"Public DEV API http://74.48.78.17:16667 health=200 live=200 with DB live ready and runtime durable adapter blocked; frontend http://74.48.78.17:16666/=200.",
|
||||
"health:hwlab-edge-proxy:dev:ok",
|
||||
"live:hwlab-cloud-api:degraded:db-blocked"
|
||||
"live:hwlab-cloud-api:degraded:runtime-durable-adapter-blocked:runtime_durable_adapter_query_blocked",
|
||||
"db-live:ready=true:connected=true:liveDbEvidence=true",
|
||||
"runtime-durable-adapter:adapter=postgres:blocker=runtime_durable_adapter_query_blocked:migration=0001_cloud_core_skeleton:migrationChecked=false:migrationReady=false:queryResult=query_blocked"
|
||||
],
|
||||
"summary": "Blocked at DB live readiness before scheduling a DEV agent task."
|
||||
"summary": "Blocked at runtime durable adapter readiness before scheduling a DEV agent task."
|
||||
},
|
||||
{
|
||||
"milestone": "M5",
|
||||
@@ -878,13 +927,13 @@
|
||||
],
|
||||
"evidence": [
|
||||
"http://74.48.78.17:16666/ -> HTTP 200 text/html, title=HWLAB DEV MVP Gate",
|
||||
"http://74.48.78.17:16667/health -> HTTP 200 serviceId=hwlab-edge-proxy status=ok commit=cb35ada6860653b27269b0a57991184118cbf4b1",
|
||||
"http://74.48.78.17:16667/health/live -> HTTP 200 serviceId=hwlab-cloud-api status=degraded db.ready=false db.connected=false db.connectionChecked=false",
|
||||
"dev-edge-health active report -> blocked by DB live readiness, while public 16667 TCP/HTTP and frp control/tunnel health are reachable",
|
||||
"http://74.48.78.17:16667/health -> HTTP 200 serviceId=hwlab-edge-proxy status=ok commit=d881a50",
|
||||
"http://74.48.78.17:16667/health/live -> HTTP 200 serviceId=hwlab-cloud-api status=degraded db.ready=true db.connected=true db.liveDbEvidence=true runtime.blocker=runtime_durable_adapter_query_blocked runtime.migration=0001_cloud_core_skeleton",
|
||||
"dev-edge-health active report remains older DB-live evidence and is superseded for M4/M5 blocker naming by current d881a50 M4 preflight evidence",
|
||||
"dev-m3-hardware-loop active report -> blocked, classification=hardware loop, summary=patch-panel active DO1 -> DI1 connection missing",
|
||||
"dev-m4-agent-loop active report -> blocked, classification=DB live, summary=cloud-api /health/live reports DB degraded; connected=false; ready=false"
|
||||
"dev-m4-agent-loop active report -> blocked, classification=runtime_durable_adapter_query_blocked, summary=runtime durable adapter query/migration readiness is blocked; skills commit/version injection is incomplete"
|
||||
],
|
||||
"summary": "Public DEV route/frp is reachable on 16666/16667, but live MVP remains blocked by DB live readiness and the M3 hardware loop topology; no historical 6667 failure is counted as active evidence."
|
||||
"summary": "Public DEV route/frp is reachable on 16666/16667, but live MVP remains blocked by runtime_durable_adapter_query_blocked, skills commit/version injection, and the M3 hardware loop topology; no DB-live-only blocker is counted as current M4/M5 evidence."
|
||||
}
|
||||
],
|
||||
"levels": {
|
||||
@@ -1050,7 +1099,7 @@
|
||||
"status": "blocked",
|
||||
"category": "agent-loop-live-preflight",
|
||||
"reportPath": "reports/dev-gate/dev-m4-agent-loop.json",
|
||||
"summary": "Blocked at DB live readiness before scheduling a DEV agent task."
|
||||
"summary": "Blocked at runtime durable adapter readiness before scheduling a DEV agent task."
|
||||
},
|
||||
{
|
||||
"milestone": "M5",
|
||||
@@ -1060,7 +1109,7 @@
|
||||
"status": "blocked",
|
||||
"category": "mvp-e2e-live",
|
||||
"reportPath": "reports/dev-gate/dev-mvp-gate-report.json",
|
||||
"summary": "Public DEV route/frp is reachable on 16666/16667, but live MVP remains blocked by DB live readiness and the M3 hardware loop topology; no historical 6667 failure is counted as active evidence."
|
||||
"summary": "Public DEV route/frp is reachable on 16666/16667, but live MVP remains blocked by runtime_durable_adapter_query_blocked, skills commit/version injection, and the M3 hardware loop topology; no DB-live-only blocker is counted as current M4/M5 evidence."
|
||||
},
|
||||
{
|
||||
"priority": "P1",
|
||||
@@ -1105,56 +1154,36 @@
|
||||
{
|
||||
"priority": "P1",
|
||||
"order": 5,
|
||||
"type": "runtime_blocker",
|
||||
"scope": "cloud-api-db",
|
||||
"sourceIssue": "pikasTech/HWLAB#36",
|
||||
"source": "reports/dev-gate/dev-edge-health.json",
|
||||
"summary": "DB endpoint DNS resolution failed from the cloud-api runtime"
|
||||
},
|
||||
{
|
||||
"priority": "P1",
|
||||
"order": 5,
|
||||
"type": "network_blocker",
|
||||
"scope": "cloud-api-db",
|
||||
"sourceIssue": "pikasTech/HWLAB#34",
|
||||
"source": "reports/dev-gate/dev-preflight-report.json",
|
||||
"summary": "DB endpoint DNS resolution failed from the cloud-api runtime",
|
||||
"nextTask": "Deploy cloud-api DB runtime readiness probe and/or repair DEV DB connectivity, then rerun the read-only health smoke without reading or printing the DB secret value."
|
||||
},
|
||||
{
|
||||
"priority": "P1",
|
||||
"order": 5,
|
||||
"type": "runtime_blocker",
|
||||
"scope": "cloud-api-db-health-gate",
|
||||
"sourceIssue": "pikasTech/HWLAB#34",
|
||||
"source": "reports/dev-gate/dev-preflight-report.json",
|
||||
"summary": "cloud-api DB runtime env is not ready; missing HWLAB_CLOUD_DB_URL, HWLAB_CLOUD_DB_SSL_MODE.",
|
||||
"nextTask": "Configure DEV hwlab-cloud-api with Secret hwlab-cloud-api-dev-db/database-url and HWLAB_CLOUD_DB_SSL_MODE=require, then rerun health/preflight without printing the secret value."
|
||||
},
|
||||
{
|
||||
"priority": "P1",
|
||||
"order": 5,
|
||||
"type": "runtime_blocker",
|
||||
"scope": "db-live",
|
||||
"type": "agent_blocker",
|
||||
"scope": "agent-mgr-health",
|
||||
"sourceIssue": "pikasTech/HWLAB#37",
|
||||
"source": "reports/dev-gate/dev-m4-agent-loop.json",
|
||||
"summary": "cloud-api /health/live reports DB degraded; connected=false; ready=false."
|
||||
"summary": "hwlab-agent-mgr /health/live is degraded."
|
||||
},
|
||||
{
|
||||
"priority": "P1",
|
||||
"order": 5,
|
||||
"type": "runtime_blocker",
|
||||
"scope": "db-live",
|
||||
"sourceIssue": "pikasTech/HWLAB#39",
|
||||
"source": "reports/dev-gate/dev-mvp-gate-report.json",
|
||||
"summary": "cloud-api /health/live reports DB degraded; db.ready=false, db.connected=false, and live DB evidence is not established."
|
||||
"scope": "runtime-durable-adapter",
|
||||
"sourceIssue": "pikasTech/HWLAB#164",
|
||||
"source": "reports/dev-gate/dev-m4-agent-loop.json",
|
||||
"summary": "cloud-api durable runtime adapter is blocked: runtime_durable_adapter_query_blocked; adapter=postgres; durable=false; ready=false; migration=0001_cloud_core_skeleton checked=false ready=false missing=true; queryResult=query_blocked."
|
||||
},
|
||||
{
|
||||
"priority": "P1",
|
||||
"order": 5,
|
||||
"type": "agent_blocker",
|
||||
"scope": "skills-commit-version-injection",
|
||||
"sourceIssue": "pikasTech/HWLAB#37",
|
||||
"source": "reports/dev-gate/dev-m4-agent-loop.json",
|
||||
"summary": "DEV skills injection is incomplete: missing hwlab-agent-skills.HWLAB_SKILLS_VERSION, worker-dry-run.HWLAB_SKILL_VERSION_FROM_DEV."
|
||||
},
|
||||
{
|
||||
"priority": "P0",
|
||||
"order": 6,
|
||||
"type": "runtime_blocker",
|
||||
"scope": "m3-box-simu-identity",
|
||||
"sourceIssue": "pikasTech/HWLAB#38",
|
||||
"sourceIssue": "pikasTech/HWLAB#64",
|
||||
"source": "reports/dev-gate/dev-m3-hardware-loop.json",
|
||||
"summary": "DEV exposes two box-simu endpoints, but live identities are not the required distinct resources res_boxsimu_1 and res_boxsimu_2; observed resources=res_boxsimu_1."
|
||||
},
|
||||
@@ -1163,7 +1192,7 @@
|
||||
"order": 6,
|
||||
"type": "runtime_blocker",
|
||||
"scope": "m3-gateway-simu-identity",
|
||||
"sourceIssue": "pikasTech/HWLAB#38",
|
||||
"sourceIssue": "pikasTech/HWLAB#64",
|
||||
"source": "reports/dev-gate/dev-m3-hardware-loop.json",
|
||||
"summary": "DEV exposes two gateway-simu endpoints, but live gateway identities are not distinct; observed identities=gateway-a:gws_gateway-a."
|
||||
},
|
||||
@@ -1172,7 +1201,7 @@
|
||||
"order": 6,
|
||||
"type": "runtime_blocker",
|
||||
"scope": "m3-patch-panel-wiring",
|
||||
"sourceIssue": "pikasTech/HWLAB#38",
|
||||
"sourceIssue": "pikasTech/HWLAB#64",
|
||||
"source": "reports/dev-gate/dev-m3-hardware-loop.json",
|
||||
"summary": "DEV patch-panel is callable, but live wiring does not contain res_boxsimu_1:DO1 -> res_boxsimu_2:DI1; active=res_boxsim_alpha:uart0->res_boxsim_beta:uart0, res_boxsim_alpha:gpio0->res_boxsim_beta:gpio0; configured=res_boxsim_alpha:uart0->res_boxsim_beta:uart0, res_boxsim_alpha:gpio0->res_boxsim_beta:gpio0."
|
||||
},
|
||||
@@ -1185,15 +1214,6 @@
|
||||
"source": "reports/dev-gate/dev-mvp-gate-report.json",
|
||||
"summary": "Live M3 smoke reached DEV simulators, but patch-panel active DO1 -> DI1 connection is missing."
|
||||
},
|
||||
{
|
||||
"priority": "P3",
|
||||
"order": 99,
|
||||
"type": "agent_blocker",
|
||||
"scope": "code-agent-provider-secret",
|
||||
"sourceIssue": "pikasTech/HWLAB#36",
|
||||
"source": "reports/dev-gate/dev-edge-health.json",
|
||||
"summary": "Code Agent provider Secret hwlab-code-agent-provider/openai-api-key is not present as key-presence evidence; #143 real provider-backed chat remains blocked"
|
||||
},
|
||||
{
|
||||
"priority": "P3",
|
||||
"order": 99,
|
||||
@@ -1202,24 +1222,6 @@
|
||||
"sourceIssue": "pikasTech/HWLAB#38",
|
||||
"source": "reports/dev-gate/dev-m3-hardware-loop.json",
|
||||
"summary": "Plan-only mode is intentionally non-mutating; run the bounded live smoke only after explicit DEV/non-PROD approval and after read-only preconditions identify the exact HWLAB targets."
|
||||
},
|
||||
{
|
||||
"priority": "P3",
|
||||
"order": 99,
|
||||
"type": "agent_blocker",
|
||||
"scope": "agent-mgr-health",
|
||||
"sourceIssue": "pikasTech/HWLAB#37",
|
||||
"source": "reports/dev-gate/dev-m4-agent-loop.json",
|
||||
"summary": "hwlab-agent-mgr /health/live is degraded."
|
||||
},
|
||||
{
|
||||
"priority": "P3",
|
||||
"order": 99,
|
||||
"type": "agent_blocker",
|
||||
"scope": "skills-commit-version-injection",
|
||||
"sourceIssue": "pikasTech/HWLAB#37",
|
||||
"source": "reports/dev-gate/dev-m4-agent-loop.json",
|
||||
"summary": "DEV skills injection is incomplete: missing hwlab-agent-skills.HWLAB_SKILLS_VERSION, worker-dry-run.HWLAB_SKILL_VERSION_FROM_DEV."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1300,89 +1302,55 @@
|
||||
"rationale": "Runner read-only observability must be repaired without treating the runner gap as proof that D601 k3s or public DEV endpoints are unavailable."
|
||||
},
|
||||
{
|
||||
"id": "dev-edge-health:cloud-api-db",
|
||||
"id": "dev-m4-agent-loop:agent-mgr-health",
|
||||
"priority": "P1",
|
||||
"type": "runtime_blocker",
|
||||
"scope": "cloud-api-db",
|
||||
"status": "open",
|
||||
"source": "reports/dev-gate/dev-edge-health.json",
|
||||
"sourceIssue": "pikasTech/HWLAB#36",
|
||||
"summary": "DB endpoint DNS resolution failed from the cloud-api runtime",
|
||||
"unblockOrder": 5,
|
||||
"unblocks": [
|
||||
"pikasTech/HWLAB#34",
|
||||
"pikasTech/HWLAB#33",
|
||||
"pikasTech/HWLAB#39"
|
||||
],
|
||||
"rationale": "Cloud API DB env and health readiness block runtime health and MVP evidence even if ingress starts responding."
|
||||
},
|
||||
{
|
||||
"id": "dev-gate-preflight:cloud-api-db",
|
||||
"priority": "P1",
|
||||
"type": "network_blocker",
|
||||
"scope": "cloud-api-db",
|
||||
"status": "open",
|
||||
"source": "reports/dev-gate/dev-preflight-report.json",
|
||||
"sourceIssue": "pikasTech/HWLAB#34",
|
||||
"summary": "DB endpoint DNS resolution failed from the cloud-api runtime",
|
||||
"nextTask": "Deploy cloud-api DB runtime readiness probe and/or repair DEV DB connectivity, then rerun the read-only health smoke without reading or printing the DB secret value.",
|
||||
"unblockOrder": 5,
|
||||
"unblocks": [
|
||||
"pikasTech/HWLAB#34",
|
||||
"pikasTech/HWLAB#33",
|
||||
"pikasTech/HWLAB#39"
|
||||
],
|
||||
"rationale": "Cloud API DB env and health readiness block runtime health and MVP evidence even if ingress starts responding."
|
||||
},
|
||||
{
|
||||
"id": "dev-gate-preflight:cloud-api-db-health-gate",
|
||||
"priority": "P1",
|
||||
"type": "runtime_blocker",
|
||||
"scope": "cloud-api-db-health-gate",
|
||||
"status": "open",
|
||||
"source": "reports/dev-gate/dev-preflight-report.json",
|
||||
"sourceIssue": "pikasTech/HWLAB#34",
|
||||
"summary": "cloud-api DB runtime env is not ready; missing HWLAB_CLOUD_DB_URL, HWLAB_CLOUD_DB_SSL_MODE.",
|
||||
"nextTask": "Configure DEV hwlab-cloud-api with Secret hwlab-cloud-api-dev-db/database-url and HWLAB_CLOUD_DB_SSL_MODE=require, then rerun health/preflight without printing the secret value.",
|
||||
"unblockOrder": 5,
|
||||
"unblocks": [
|
||||
"pikasTech/HWLAB#34",
|
||||
"pikasTech/HWLAB#33",
|
||||
"pikasTech/HWLAB#39"
|
||||
],
|
||||
"rationale": "Cloud API DB env and health readiness block runtime health and MVP evidence even if ingress starts responding."
|
||||
},
|
||||
{
|
||||
"id": "dev-m4-agent-loop:db-live",
|
||||
"priority": "P1",
|
||||
"type": "runtime_blocker",
|
||||
"scope": "db-live",
|
||||
"type": "agent_blocker",
|
||||
"scope": "agent-mgr-health",
|
||||
"status": "open",
|
||||
"source": "reports/dev-gate/dev-m4-agent-loop.json",
|
||||
"sourceIssue": "pikasTech/HWLAB#37",
|
||||
"summary": "cloud-api /health/live reports DB degraded; connected=false; ready=false.",
|
||||
"summary": "hwlab-agent-mgr /health/live is degraded.",
|
||||
"unblockOrder": 5,
|
||||
"unblocks": [
|
||||
"pikasTech/HWLAB#37",
|
||||
"pikasTech/HWLAB#39"
|
||||
"pikasTech/HWLAB#39",
|
||||
"pikasTech/HWLAB#164"
|
||||
],
|
||||
"rationale": "M4 and M5 cannot claim live agent or MVP evidence until cloud-api /health/live proves DB readiness with redacted live evidence."
|
||||
"rationale": "M4/M5 agent evidence needs deployed manager, skills, and worker paths to expose explicit skills commit and version; session-mode-only worker templates are not enough."
|
||||
},
|
||||
{
|
||||
"id": "dev-mvp-gate-report:db-live",
|
||||
"id": "dev-m4-agent-loop:runtime-durable-adapter",
|
||||
"priority": "P1",
|
||||
"type": "runtime_blocker",
|
||||
"scope": "db-live",
|
||||
"scope": "runtime-durable-adapter",
|
||||
"status": "open",
|
||||
"source": "reports/dev-gate/dev-mvp-gate-report.json",
|
||||
"sourceIssue": "pikasTech/HWLAB#39",
|
||||
"summary": "cloud-api /health/live reports DB degraded; db.ready=false, db.connected=false, and live DB evidence is not established.",
|
||||
"source": "reports/dev-gate/dev-m4-agent-loop.json",
|
||||
"sourceIssue": "pikasTech/HWLAB#164",
|
||||
"summary": "cloud-api durable runtime adapter is blocked: runtime_durable_adapter_query_blocked; adapter=postgres; durable=false; ready=false; migration=0001_cloud_core_skeleton checked=false ready=false missing=true; queryResult=query_blocked.",
|
||||
"unblockOrder": 5,
|
||||
"unblocks": [
|
||||
"pikasTech/HWLAB#37",
|
||||
"pikasTech/HWLAB#39"
|
||||
"pikasTech/HWLAB#39",
|
||||
"pikasTech/HWLAB#164"
|
||||
],
|
||||
"rationale": "M4 and M5 cannot claim live agent or MVP evidence until cloud-api /health/live proves DB readiness with redacted live evidence."
|
||||
"rationale": "M4 and M5 cannot claim live agent or MVP evidence until the cloud-api postgres runtime adapter proves schema, migration, and read-query durability; DB live evidence alone is not durability evidence."
|
||||
},
|
||||
{
|
||||
"id": "dev-m4-agent-loop:skills-commit-version-injection",
|
||||
"priority": "P1",
|
||||
"type": "agent_blocker",
|
||||
"scope": "skills-commit-version-injection",
|
||||
"status": "open",
|
||||
"source": "reports/dev-gate/dev-m4-agent-loop.json",
|
||||
"sourceIssue": "pikasTech/HWLAB#37",
|
||||
"summary": "DEV skills injection is incomplete: missing hwlab-agent-skills.HWLAB_SKILLS_VERSION, worker-dry-run.HWLAB_SKILL_VERSION_FROM_DEV.",
|
||||
"unblockOrder": 5,
|
||||
"unblocks": [
|
||||
"pikasTech/HWLAB#37",
|
||||
"pikasTech/HWLAB#39",
|
||||
"pikasTech/HWLAB#164"
|
||||
],
|
||||
"rationale": "M4/M5 agent evidence needs deployed manager, skills, and worker paths to expose explicit skills commit and version; session-mode-only worker templates are not enough."
|
||||
},
|
||||
{
|
||||
"id": "dev-m3-hardware-loop:m3-box-simu-identity",
|
||||
@@ -1391,7 +1359,7 @@
|
||||
"scope": "m3-box-simu-identity",
|
||||
"status": "open",
|
||||
"source": "reports/dev-gate/dev-m3-hardware-loop.json",
|
||||
"sourceIssue": "pikasTech/HWLAB#38",
|
||||
"sourceIssue": "pikasTech/HWLAB#64",
|
||||
"summary": "DEV exposes two box-simu endpoints, but live identities are not the required distinct resources res_boxsimu_1 and res_boxsimu_2; observed resources=res_boxsimu_1.",
|
||||
"unblockOrder": 6,
|
||||
"unblocks": [
|
||||
@@ -1408,7 +1376,7 @@
|
||||
"scope": "m3-gateway-simu-identity",
|
||||
"status": "open",
|
||||
"source": "reports/dev-gate/dev-m3-hardware-loop.json",
|
||||
"sourceIssue": "pikasTech/HWLAB#38",
|
||||
"sourceIssue": "pikasTech/HWLAB#64",
|
||||
"summary": "DEV exposes two gateway-simu endpoints, but live gateway identities are not distinct; observed identities=gateway-a:gws_gateway-a.",
|
||||
"unblockOrder": 6,
|
||||
"unblocks": [
|
||||
@@ -1425,7 +1393,7 @@
|
||||
"scope": "m3-patch-panel-wiring",
|
||||
"status": "open",
|
||||
"source": "reports/dev-gate/dev-m3-hardware-loop.json",
|
||||
"sourceIssue": "pikasTech/HWLAB#38",
|
||||
"sourceIssue": "pikasTech/HWLAB#64",
|
||||
"summary": "DEV patch-panel is callable, but live wiring does not contain res_boxsimu_1:DO1 -> res_boxsimu_2:DI1; active=res_boxsim_alpha:uart0->res_boxsim_beta:uart0, res_boxsim_alpha:gpio0->res_boxsim_beta:gpio0; configured=res_boxsim_alpha:uart0->res_boxsim_beta:uart0, res_boxsim_alpha:gpio0->res_boxsim_beta:gpio0.",
|
||||
"unblockOrder": 6,
|
||||
"unblocks": [
|
||||
@@ -1452,21 +1420,6 @@
|
||||
],
|
||||
"rationale": "M3 remains blocked until the real DEV hardware trusted loop proves DO1 -> patch-panel -> DI1 with operation, trace, audit, and evidence identifiers."
|
||||
},
|
||||
{
|
||||
"id": "dev-edge-health:code-agent-provider-secret",
|
||||
"priority": "P3",
|
||||
"type": "agent_blocker",
|
||||
"scope": "code-agent-provider-secret",
|
||||
"status": "open",
|
||||
"source": "reports/dev-gate/dev-edge-health.json",
|
||||
"sourceIssue": "pikasTech/HWLAB#36",
|
||||
"summary": "Code Agent provider Secret hwlab-code-agent-provider/openai-api-key is not present as key-presence evidence; #143 real provider-backed chat remains blocked",
|
||||
"unblockOrder": 99,
|
||||
"unblocks": [
|
||||
"pikasTech/HWLAB#39"
|
||||
],
|
||||
"rationale": "Residual blocker that must be classified before claiming a green DEV gate."
|
||||
},
|
||||
{
|
||||
"id": "dev-m3-hardware-loop:m3-live-write-authorization",
|
||||
"priority": "P3",
|
||||
@@ -1481,36 +1434,6 @@
|
||||
"pikasTech/HWLAB#39"
|
||||
],
|
||||
"rationale": "Residual blocker that must be classified before claiming a green DEV gate."
|
||||
},
|
||||
{
|
||||
"id": "dev-m4-agent-loop:agent-mgr-health",
|
||||
"priority": "P3",
|
||||
"type": "agent_blocker",
|
||||
"scope": "agent-mgr-health",
|
||||
"status": "open",
|
||||
"source": "reports/dev-gate/dev-m4-agent-loop.json",
|
||||
"sourceIssue": "pikasTech/HWLAB#37",
|
||||
"summary": "hwlab-agent-mgr /health/live is degraded.",
|
||||
"unblockOrder": 99,
|
||||
"unblocks": [
|
||||
"pikasTech/HWLAB#39"
|
||||
],
|
||||
"rationale": "Residual blocker that must be classified before claiming a green DEV gate."
|
||||
},
|
||||
{
|
||||
"id": "dev-m4-agent-loop:skills-commit-version-injection",
|
||||
"priority": "P3",
|
||||
"type": "agent_blocker",
|
||||
"scope": "skills-commit-version-injection",
|
||||
"status": "open",
|
||||
"source": "reports/dev-gate/dev-m4-agent-loop.json",
|
||||
"sourceIssue": "pikasTech/HWLAB#37",
|
||||
"summary": "DEV skills injection is incomplete: missing hwlab-agent-skills.HWLAB_SKILLS_VERSION, worker-dry-run.HWLAB_SKILL_VERSION_FROM_DEV.",
|
||||
"unblockOrder": 99,
|
||||
"unblocks": [
|
||||
"pikasTech/HWLAB#39"
|
||||
],
|
||||
"rationale": "Residual blocker that must be classified before claiming a green DEV gate."
|
||||
}
|
||||
],
|
||||
"nextSteps": [
|
||||
@@ -1557,20 +1480,18 @@
|
||||
"blockerOrder": 5,
|
||||
"priority": "P1",
|
||||
"scopes": [
|
||||
"cloud-api-db",
|
||||
"cloud-api-db-health-gate",
|
||||
"db-live"
|
||||
"agent-mgr-health",
|
||||
"runtime-durable-adapter",
|
||||
"skills-commit-version-injection"
|
||||
],
|
||||
"sourceIssues": [
|
||||
"pikasTech/HWLAB#33",
|
||||
"pikasTech/HWLAB#34",
|
||||
"pikasTech/HWLAB#36",
|
||||
"pikasTech/HWLAB#164",
|
||||
"pikasTech/HWLAB#37",
|
||||
"pikasTech/HWLAB#39"
|
||||
],
|
||||
"rationale": "Cloud API DB env and health readiness block runtime health and MVP evidence even if ingress starts responding.",
|
||||
"action": "Deploy cloud-api DB runtime readiness probe and/or repair DEV DB connectivity, then rerun the read-only health smoke without reading or printing the DB secret value.",
|
||||
"evidenceRequired": "Cloud API health/live output showing DB env ready, endpointSource=secret-url-host, redacted secret references, and no secret material."
|
||||
"rationale": "M4/M5 agent evidence needs deployed manager, skills, and worker paths to expose explicit skills commit and version; session-mode-only worker templates are not enough.",
|
||||
"action": "Inject explicit skills commit and version into agent manager, skills service, and worker jobs, then rerun the M4 read-only/live preflight.",
|
||||
"evidenceRequired": "Read-only hwlab-agent-mgr/hwlab-agent-skills health plus worker dry-run manifest showing skillCommitId/skillVersion and HWLAB_SKILL_COMMIT_ID/HWLAB_SKILL_VERSION injected."
|
||||
},
|
||||
{
|
||||
"order": 4,
|
||||
@@ -1596,14 +1517,9 @@
|
||||
"blockerOrder": 99,
|
||||
"priority": "P3",
|
||||
"scopes": [
|
||||
"code-agent-provider-secret",
|
||||
"m3-live-write-authorization",
|
||||
"agent-mgr-health",
|
||||
"skills-commit-version-injection"
|
||||
"m3-live-write-authorization"
|
||||
],
|
||||
"sourceIssues": [
|
||||
"pikasTech/HWLAB#36",
|
||||
"pikasTech/HWLAB#37",
|
||||
"pikasTech/HWLAB#38",
|
||||
"pikasTech/HWLAB#39"
|
||||
],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# HWLAB M5 DEV Gate Aggregator v2
|
||||
|
||||
Status: blocked
|
||||
Generated from: `96e802b2a22c`
|
||||
Generated from: `66586ccf109e`
|
||||
Scope: DEV only, report-only
|
||||
Active frontend: `http://74.48.78.17:16666/`
|
||||
Active API/live: `http://74.48.78.17:16667/health/live`
|
||||
@@ -9,7 +9,7 @@ Deprecated public endpoints: `http://74.48.78.17:6666`, `http://74.48.78.17:6667
|
||||
|
||||
## Summary
|
||||
|
||||
Frontend revision 1e8805664970839b72be40c34636b08f6d18b131 is usable in degraded/read-only mode and EDGE/ROUTE DEV-LIVE evidence exists on :16666/:16667, but M5 remains blocked by artifact source drift, API/runtime durability degradation, missing M3 trusted loop operation evidence, and blocked M4 agent-loop preflight.
|
||||
Frontend revision 1e8805664970839b72be40c34636b08f6d18b131 is usable in degraded/read-only mode and EDGE/ROUTE DEV-LIVE evidence exists on :16666/:16667, but M5 remains blocked by artifact source drift, runtime durable adapter or skills injection readiness, missing M3 trusted loop operation evidence, and blocked M4 agent-loop preflight.
|
||||
|
||||
## Frontend DEV Fact
|
||||
|
||||
@@ -21,10 +21,13 @@ The latest #99/#108 frontend DEV visibility fact is revision `1e8805664970839b72
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Frontend DEV revision | pass | DEV-LIVE | http://74.48.78.17:16666/ serves the Cloud Workbench frontend revision 1e8805664970839b72be40c34636b08f6d18b131; deployed UI is usable in degraded/read-only mode only and this is browser/frontend evidence only. | Keep frontend revision proof separate from DB live readiness, M3 hardware-loop evidence, M4 agent-loop evidence, and M5 acceptance. |
|
||||
| EDGE/ROUTE live | pass | DEV-LIVE | http://74.48.78.17:16666/, http://74.48.78.17:16667/health, and http://74.48.78.17:16667/health/live returned observed HWLAB DEV route responses in the active M2 read-only smoke. | Keep this separated from DB readiness, M3/M4 loop evidence, and M5 acceptance. |
|
||||
| DB live/degraded | blocked | BLOCKED | cloud-api DB status=degraded; configReady=true; ready=false; connected=false; endpointSource=unknown; liveDbEvidence=false. | Provide live DB connection evidence through redacted health output; route reachability alone is insufficient. |
|
||||
| DB live/degraded | pass | DEV-LIVE | cloud-api DB status=ok; configReady=true; ready=true; connected=true; endpointSource=secret-url-host; liveDbEvidence=true. | Provide live DB connection evidence through redacted health output; route reachability alone is insufficient. |
|
||||
| Runtime durable adapter | blocked | BLOCKED | runtime adapter=postgres; durableRequested=true; durable=false; ready=false; blocker=runtime_durable_adapter_query_blocked; migration=0001_cloud_core_skeleton checked=false ready=false; queryResult=query_blocked. | Repair the postgres durable runtime adapter query/migration readiness and rerun health/M4 preflight without treating DB live as durability proof. |
|
||||
| Agent skills injection | blocked | BLOCKED | DEV skills injection is incomplete: missing hwlab-agent-skills.HWLAB_SKILLS_VERSION, worker-dry-run.HWLAB_SKILL_VERSION_FROM_DEV. | Inject explicit skill commit and version into hwlab-agent-mgr, hwlab-agent-skills, and scheduled worker jobs before claiming M4/M5 agent evidence. |
|
||||
| Code Agent provider | pass | DEV-LIVE | code-agent provider=openai-responses; status=available; ready=true. | Keep provider-backed Code Agent readiness separate from DB live and runtime durable adapter readiness. |
|
||||
| D601 runner observability | blocked | DEV-LIVE | D601 public DEV endpoints are reachable, but the runner cannot read /etc/rancher/k3s/k3s.yaml; classify as #46 runner permission/mount or read-only observability gap, not D601 global offline. Alternate read-only cluster probes are readable. runnerKubeconfigReadable=false, runnerKubeconfigProbeExitCode=0, runnerKubeconfigProbeStderr=empty, d601PublicEndpointsReachable=true, d601K3sUnavailable=false. | Treat #46 runner kubeconfig/readonly gaps separately from D601 service health; rerun read-only observability after the mount or permission path is repaired. |
|
||||
| M3 hardware trusted loop | blocked | BLOCKED | No live DEV operation was attempted because read-only direct target checks did not prove the required patch-panel-owned M3 route. Blocker: DEV exposes two box-simu endpoints, but live identities are not the required distinct resources res_boxsimu_1 and res_boxsimu_2; observed resources=res_boxsimu_1. | Only a real DEV res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1 observation with operation/trace/audit/evidence can clear M3. |
|
||||
| M4 agent loop | blocked | BLOCKED | Blocked at DB live readiness before scheduling a DEV agent task. | Do not schedule or claim the agent loop as live until DB live and required runtime/evidence preconditions pass. |
|
||||
| M4 agent loop | blocked | BLOCKED | Blocked at runtime durable adapter readiness before scheduling a DEV agent task. | Do not schedule or claim the agent loop as live until DB live, runtime durable adapter, skills injection, and required evidence preconditions pass. |
|
||||
| artifact/desired-state source | blocked | BLOCKED | artifact targetCovered=false; artifactSource=7e29522b65c8; target=f64182b54fe6; desiredApplyMode=dry-run; mutationAttempted=false. | Refresh artifact/source coverage for current origin/main and keep desired-state apply separate from read-only route proof. |
|
||||
|
||||
## M0-M5 Level Classification
|
||||
@@ -35,7 +38,7 @@ The latest #99/#108 frontend DEV visibility fact is revision `1e8805664970839b72
|
||||
| M1 | LOCAL | pass | LOCAL | missing_or_blocked | Local smoke is green; it is not DEV-LIVE. |
|
||||
| M2 | DEV-LIVE | blocked | DEV-LIVE | pass | Current public frontend/API route evidence is DEV-LIVE for route/front-end reachability only. |
|
||||
| M3 | BLOCKED | blocked | LOCAL | missing_or_blocked | DEV-LIVE hardware trusted loop is blocked; local/source shape is not acceptance. |
|
||||
| M4 | BLOCKED | blocked | DRY-RUN | missing_or_blocked | DEV-LIVE agent loop is blocked at DB live readiness; local smoke is not acceptance. |
|
||||
| M4 | BLOCKED | blocked | DRY-RUN | missing_or_blocked | DEV-LIVE agent loop is blocked at runtime durable adapter or skills injection readiness; local smoke is not acceptance. |
|
||||
| M5 | BLOCKED | blocked | DRY-RUN | missing_or_blocked | Dry-run is green, but bounded DEV-LIVE MVP e2e is blocked. |
|
||||
|
||||
## Milestones
|
||||
@@ -58,7 +61,7 @@ The latest #99/#108 frontend DEV visibility fact is revision `1e8805664970839b72
|
||||
| artifact-publish-digests | blocked | BLOCKED | artifactState=contract-skeleton, ciPublished=false, registryVerified=false, sha256=0, not_published=13, targetCovered=false |
|
||||
| d601-k3s-observability | blocked | DEV-LIVE | D601 public DEV endpoints are reachable, but the runner cannot read /etc/rancher/k3s/k3s.yaml; classify as #46 runner permission/mount or read-only observability gap, not D601 global offline. Alternate read-only cluster probes are readable. runnerKubeconfigReadable=false, runnerKubeconfigProbeExitCode=0, runnerKubeconfigProbeStderr=empty, d601PublicEndpointsReachable=true, d601K3sUnavailable=false. |
|
||||
| dev-edge-frp-16667 | pass | DEV-LIVE | Committed edge report proves read-only public HTTP on :16667 /health and /health/live; this is route evidence, not DB/M3/M4/M5 acceptance. |
|
||||
| cloud-api-db-ready | blocked | BLOCKED | cloud-api DB status=degraded; ready=false; connected=false; endpointSource=unknown; liveDbEvidence=false. |
|
||||
| cloud-api-db-ready | pass | DEV-LIVE | cloud-api DB status=ok; ready=true; connected=true; endpointSource=secret-url-host; liveDbEvidence=true. |
|
||||
| m3-hardware-trusted-loop | blocked | BLOCKED | M3 trusted loop is blocked until res_boxsimu_1:DO1 -> patch-panel -> res_boxsimu_2:DI1 is proven with operation/trace/audit/evidence. |
|
||||
| m4-agent-loop-live | blocked | BLOCKED | M4 agent loop live path is blocked before accepted agent scheduling/evidence closure. |
|
||||
| m5-mvp-dev-live | blocked | BLOCKED | M5 dry-run passed; bounded DEV-LIVE MVP e2e has not passed. |
|
||||
@@ -68,8 +71,8 @@ The latest #99/#108 frontend DEV visibility fact is revision `1e8805664970839b72
|
||||
| Milestone | Status | Current level | Blocker class | Dependency | Required next proof |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| M3 | blocked | BLOCKED | direct-target-identity-gap | Two distinct live box-simu resources and two distinct gateway-simu identities are required before M3 can run. | Fix DEV simulator instance identity so two box-simu pods report res_boxsimu_1/res_boxsimu_2 and two gateway-simu pods report distinct gateway identities. |
|
||||
| M4 | blocked | BLOCKED | db-live-readiness | Cloud API /health/live must report DB ready=true, connected=true, endpointSource=secret-url-host, and liveDbEvidence=true before live agent scheduling/evidence closure. | Repair DB live readiness and rerun the M4 live preflight without scheduling a DEV agent task before preconditions pass. |
|
||||
| M5 | blocked | BLOCKED | composite-db-m3-m4-live | M5 needs DB live readiness, M3 trusted-loop DEV evidence, M4 live preflight/evidence closure, and current source/artifact coverage. | After DB/M3/M4 blockers are cleared, run only the bounded DEV MVP live gate command with explicit DEV/non-PROD confirmations. |
|
||||
| M4 | blocked | BLOCKED | runtime_durable_adapter_query_blocked | Cloud API /health/live must prove the postgres durable runtime adapter schema, 0001_cloud_core_skeleton migration ledger, and read-query readiness before live agent scheduling/evidence closure. | Repair the runtime durable adapter query/migration readiness and rerun the M4 live preflight without scheduling a DEV agent task before preconditions pass. |
|
||||
| M5 | blocked | BLOCKED | composite-runtime-durable-m3-m4-live | M5 needs DB live readiness, runtime durable adapter readiness, skills commit/version injection, M3 trusted-loop DEV evidence, M4 live preflight/evidence closure, and current source/artifact coverage. | After DB/runtime durable adapter/skills/M3/M4 blockers are cleared, run only the bounded DEV MVP live gate command with explicit DEV/non-PROD confirmations. |
|
||||
|
||||
## Blockers
|
||||
|
||||
@@ -79,19 +82,14 @@ The latest #99/#108 frontend DEV visibility fact is revision `1e8805664970839b72
|
||||
| P1 | 3 | contract_blocker | artifact-source-commit | source commit origin/main f64182b is not covered by artifact source 7e29522; target changes since the artifact source touch artifact build inputs. |
|
||||
| P1 | 3 | runtime_blocker | dev-artifact-publish | reports/dev-gate/dev-artifacts.json does not prove all required HWLAB service artifacts for origin/main f64182b; current status is published with 13/13 required services published and source states resolved: 13 source-present, 0 intentionally-disabled. |
|
||||
| P1 | 4 | observability_blocker | runner-kubeconfig-readonly-gap | The runner cannot read /etc/rancher/k3s/k3s.yaml; classify this as a runner permission/mount gap, not a D601 global outage. Alternate read-only cluster probes and public DEV endpoint probes are reported separately. |
|
||||
| P1 | 5 | runtime_blocker | cloud-api-db | DB endpoint DNS resolution failed from the cloud-api runtime |
|
||||
| P1 | 5 | network_blocker | cloud-api-db | DB endpoint DNS resolution failed from the cloud-api runtime |
|
||||
| P1 | 5 | runtime_blocker | cloud-api-db-health-gate | cloud-api DB runtime env is not ready; missing HWLAB_CLOUD_DB_URL, HWLAB_CLOUD_DB_SSL_MODE. |
|
||||
| P1 | 5 | runtime_blocker | db-live | cloud-api /health/live reports DB degraded; connected=false; ready=false. |
|
||||
| P1 | 5 | runtime_blocker | db-live | cloud-api /health/live reports DB degraded; db.ready=false, db.connected=false, and live DB evidence is not established. |
|
||||
| P1 | 5 | agent_blocker | agent-mgr-health | hwlab-agent-mgr /health/live is degraded. |
|
||||
| P1 | 5 | runtime_blocker | runtime-durable-adapter | cloud-api durable runtime adapter is blocked: runtime_durable_adapter_query_blocked; adapter=postgres; durable=false; ready=false; migration=0001_cloud_core_skeleton checked=false ready=false missing=true; queryResult=query_blocked. |
|
||||
| P1 | 5 | agent_blocker | skills-commit-version-injection | DEV skills injection is incomplete: missing hwlab-agent-skills.HWLAB_SKILLS_VERSION, worker-dry-run.HWLAB_SKILL_VERSION_FROM_DEV. |
|
||||
| P0 | 6 | runtime_blocker | m3-box-simu-identity | DEV exposes two box-simu endpoints, but live identities are not the required distinct resources res_boxsimu_1 and res_boxsimu_2; observed resources=res_boxsimu_1. |
|
||||
| P0 | 6 | runtime_blocker | m3-gateway-simu-identity | DEV exposes two gateway-simu endpoints, but live gateway identities are not distinct; observed identities=gateway-a:gws_gateway-a. |
|
||||
| P0 | 6 | runtime_blocker | m3-patch-panel-wiring | DEV patch-panel is callable, but live wiring does not contain res_boxsimu_1:DO1 -> res_boxsimu_2:DI1; active=res_boxsim_alpha:uart0->res_boxsim_beta:uart0, res_boxsim_alpha:gpio0->res_boxsim_beta:gpio0; configured=res_boxsim_alpha:uart0->res_boxsim_beta:uart0, res_boxsim_alpha:gpio0->res_boxsim_beta:gpio0. |
|
||||
| P0 | 6 | runtime_blocker | m3-hardware-loop-runtime | Live M3 smoke reached DEV simulators, but patch-panel active DO1 -> DI1 connection is missing. |
|
||||
| P3 | 99 | agent_blocker | code-agent-provider-secret | Code Agent provider Secret hwlab-code-agent-provider/openai-api-key is not present as key-presence evidence; #143 real provider-backed chat remains blocked |
|
||||
| P3 | 99 | safety_blocker | m3-live-write-authorization | Plan-only mode is intentionally non-mutating; run the bounded live smoke only after explicit DEV/non-PROD approval and after read-only preconditions identify the exact HWLAB targets. |
|
||||
| P3 | 99 | agent_blocker | agent-mgr-health | hwlab-agent-mgr /health/live is degraded. |
|
||||
| P3 | 99 | agent_blocker | skills-commit-version-injection | DEV skills injection is incomplete: missing hwlab-agent-skills.HWLAB_SKILLS_VERSION, worker-dry-run.HWLAB_SKILL_VERSION_FROM_DEV. |
|
||||
|
||||
## Next Unblock Order
|
||||
|
||||
@@ -99,8 +97,8 @@ The latest #99/#108 frontend DEV visibility fact is revision `1e8805664970839b72
|
||||
Evidence required: Artifact publish report with ciPublished=true, registryVerified=true, and sha256 digest for each frozen service ID.
|
||||
2. Provide the approved read-only runner kubeconfig mount or document the intended alternate KUBECONFIG path, then rerun the read-only report.
|
||||
Evidence required: Read-only report with runnerKubeconfigReadable, runnerKubeconfigProbeExitCode/stderr, d601PublicEndpointsReachable, and d601K3sUnavailable recorded separately, plus direct M3 service target discovery before any DO write.
|
||||
3. Deploy cloud-api DB runtime readiness probe and/or repair DEV DB connectivity, then rerun the read-only health smoke without reading or printing the DB secret value.
|
||||
Evidence required: Cloud API health/live output showing DB env ready, endpointSource=secret-url-host, redacted secret references, and no secret material.
|
||||
3. Inject explicit skills commit and version into agent manager, skills service, and worker jobs, then rerun the M4 read-only/live preflight.
|
||||
Evidence required: Read-only hwlab-agent-mgr/hwlab-agent-skills health plus worker dry-run manifest showing skillCommitId/skillVersion and HWLAB_SKILL_COMMIT_ID/HWLAB_SKILL_VERSION injected.
|
||||
4. Fix DEV box-simu instance identity so direct endpoints expose distinct res_boxsimu_1 and res_boxsimu_2 resources.
|
||||
Evidence required: Read-only direct box-simu /health/live and /status output showing distinct res_boxsimu_1 and res_boxsimu_2 resources.
|
||||
5. Resolve the blocker and attach source/local/dry-run/DEV-live evidence at the correct level.
|
||||
|
||||
@@ -81,13 +81,14 @@
|
||||
},
|
||||
"devPreconditions": {
|
||||
"status": "blocked",
|
||||
"classification": "DB live; hardware loop",
|
||||
"classification": "runtime durable adapter; skills injection; hardware loop",
|
||||
"requirements": [
|
||||
"http://74.48.78.17:16666/ returns the DEV browser entry",
|
||||
"http://74.48.78.17:16667/health returns HWLAB DEV edge JSON",
|
||||
"http://74.48.78.17:16667/health/live returns HWLAB cloud-api JSON with DB live readiness",
|
||||
"http://74.48.78.17:16667/health/live returns HWLAB cloud-api JSON with DB live readiness and runtime durability separated",
|
||||
"Runtime durable adapter proves postgres schema, migration 0001_cloud_core_skeleton, and read-query readiness before M4/M5 can promote",
|
||||
"Agent manager, skills service, and worker jobs expose explicit skill commit/version before M4/M5 can promote",
|
||||
"M3 hardware loop proves box-simu-1 DO1 -> box-simu-2 DI1 via patch-panel",
|
||||
"M4 agent runtime/evidence path is only attempted after DB live and M3 readiness are not blocked",
|
||||
"Keep the run DEV-only and avoid PROD, heavy e2e, secrets, restarts, or UniDesk substitution"
|
||||
],
|
||||
"commands": [
|
||||
@@ -99,21 +100,30 @@
|
||||
],
|
||||
"evidence": [
|
||||
"http://74.48.78.17:16666/ -> HTTP 200 text/html, title=HWLAB DEV MVP Gate",
|
||||
"http://74.48.78.17:16667/health -> HTTP 200 serviceId=hwlab-edge-proxy status=ok commit=cb35ada6860653b27269b0a57991184118cbf4b1",
|
||||
"http://74.48.78.17:16667/health/live -> HTTP 200 serviceId=hwlab-cloud-api status=degraded db.ready=false db.connected=false db.connectionChecked=false",
|
||||
"dev-edge-health active report -> blocked by DB live readiness, while public 16667 TCP/HTTP and frp control/tunnel health are reachable",
|
||||
"http://74.48.78.17:16667/health -> HTTP 200 serviceId=hwlab-edge-proxy status=ok commit=d881a50",
|
||||
"http://74.48.78.17:16667/health/live -> HTTP 200 serviceId=hwlab-cloud-api status=degraded db.ready=true db.connected=true db.liveDbEvidence=true runtime.blocker=runtime_durable_adapter_query_blocked runtime.migration=0001_cloud_core_skeleton",
|
||||
"dev-edge-health active report remains older DB-live evidence and is superseded for M4/M5 blocker naming by current d881a50 M4 preflight evidence",
|
||||
"dev-m3-hardware-loop active report -> blocked, classification=hardware loop, summary=patch-panel active DO1 -> DI1 connection missing",
|
||||
"dev-m4-agent-loop active report -> blocked, classification=DB live, summary=cloud-api /health/live reports DB degraded; connected=false; ready=false"
|
||||
"dev-m4-agent-loop active report -> blocked, classification=runtime_durable_adapter_query_blocked, summary=runtime durable adapter query/migration readiness is blocked; skills commit/version injection is incomplete"
|
||||
],
|
||||
"summary": "Public DEV route/frp is reachable on 16666/16667, but live MVP remains blocked by DB live readiness and the M3 hardware loop topology; no historical 6667 failure is counted as active evidence."
|
||||
"summary": "Public DEV route/frp is reachable on 16666/16667, but live MVP remains blocked by runtime_durable_adapter_query_blocked, skills commit/version injection, and the M3 hardware loop topology; no DB-live-only blocker is counted as current M4/M5 evidence."
|
||||
},
|
||||
"blockers": [
|
||||
{
|
||||
"type": "runtime_blocker",
|
||||
"scope": "db-live",
|
||||
"scope": "runtime-durable-adapter",
|
||||
"status": "open",
|
||||
"classification": "DB live",
|
||||
"summary": "cloud-api /health/live reports DB degraded; db.ready=false, db.connected=false, and live DB evidence is not established."
|
||||
"sourceIssue": "pikasTech/HWLAB#164",
|
||||
"classification": "runtime_durable_adapter_query_blocked",
|
||||
"summary": "cloud-api durable runtime adapter is blocked: runtime_durable_adapter_query_blocked; migration 0001_cloud_core_skeleton is missing or not checked."
|
||||
},
|
||||
{
|
||||
"type": "agent_blocker",
|
||||
"scope": "skills-commit-version-injection",
|
||||
"status": "open",
|
||||
"sourceIssue": "pikasTech/HWLAB#164",
|
||||
"classification": "skills injection",
|
||||
"summary": "DEV skills injection is incomplete: hwlab-agent-skills exposes HWLAB_SKILLS_COMMIT_ID=d881a50 but no HWLAB_SKILLS_VERSION; worker template only exposes session mode unless commit/version are injected."
|
||||
},
|
||||
{
|
||||
"type": "runtime_blocker",
|
||||
@@ -196,10 +206,10 @@
|
||||
],
|
||||
"evidence": [
|
||||
"[m4-smoke] ok m4-agent-automation-loop-local-contract-smoke",
|
||||
"Live DEV M4 preflight blocked before agent scheduling: cloud-api /health/live DB degraded, ready=false, connected=false"
|
||||
"Live DEV M4 preflight blocked before agent scheduling: runtime_durable_adapter_query_blocked; migration 0001_cloud_core_skeleton missing/not checked; skills version injection missing"
|
||||
],
|
||||
"summary": "Local M4 remains green, but active DEV-LIVE M4 is blocked at DB live readiness before agent runtime scheduling.",
|
||||
"blocker": "DB live"
|
||||
"summary": "Local M4 remains green, but active DEV-LIVE M4 is blocked at runtime durable adapter readiness and skills commit/version injection before agent runtime scheduling.",
|
||||
"blocker": "runtime_durable_adapter_query_blocked; skills injection"
|
||||
},
|
||||
{
|
||||
"id": "M5",
|
||||
@@ -213,23 +223,28 @@
|
||||
"hwlab-cli health -> status: ok, environment: dev, endpoint: http://74.48.78.17:16667, gateStatus: blocked",
|
||||
"hwlab-cli dry-run -> 9 steps, 13 artifacts, 14 health contracts, 2 hardware operations, 2 evidence records, 0 network calls",
|
||||
"M5 MVP E2E dry-run passed: 9 steps, 13 artifacts, 14 health contracts, 2 hardware operations, 2 evidence records, 0 network calls",
|
||||
"Live MVP remains blocked by DB live and M3 hardware loop active reports"
|
||||
"Live MVP remains blocked by runtime durable adapter, skills injection, and M3 hardware loop active reports"
|
||||
],
|
||||
"summary": "The M5 orchestration is green in dry-run mode, but active DEV-LIVE acceptance is blocked by DB live and hardware loop evidence.",
|
||||
"blocker": "DB live; hardware loop"
|
||||
"summary": "The M5 orchestration is green in dry-run mode, but active DEV-LIVE acceptance is blocked by runtime durable adapter, skills injection, and hardware loop evidence.",
|
||||
"blocker": "runtime durable adapter; skills injection; hardware loop"
|
||||
}
|
||||
],
|
||||
"notes": "Active #64 DEV retest report. Public 16666/16667 route is reachable; live MVP remains blocked. No PROD, secret read, runtime restart, long-running agent task, or UniDesk runtime substitution was used.",
|
||||
"notes": "Active #64 DEV retest report updated for current d881a50 evidence. Public 16666/16667 route and DB live evidence are reachable; live MVP remains blocked. No PROD, secret read, runtime restart, long-running agent task, or UniDesk runtime substitution was used.",
|
||||
"blockedClassification": [
|
||||
{
|
||||
"category": "DB live",
|
||||
"category": "runtime durable adapter",
|
||||
"status": "blocked",
|
||||
"evidence": "16667/health/live serviceId=hwlab-cloud-api status=degraded db.ready=false db.connected=false"
|
||||
"evidence": "runtime_durable_adapter_query_blocked; migration 0001_cloud_core_skeleton missing/not checked; db.liveDbEvidence=true is not durability evidence"
|
||||
},
|
||||
{
|
||||
"category": "skills injection",
|
||||
"status": "blocked",
|
||||
"evidence": "hwlab-agent-skills has HWLAB_SKILLS_COMMIT_ID=d881a50 but no HWLAB_SKILLS_VERSION; agent manager health misses skillCommitId/skillVersion"
|
||||
},
|
||||
{
|
||||
"category": "agent runtime",
|
||||
"status": "not_run",
|
||||
"evidence": "M4 stopped before agent scheduling because DB live is blocked"
|
||||
"evidence": "M4 stopped before agent scheduling because runtime durability and skills injection are blocked"
|
||||
},
|
||||
{
|
||||
"category": "hardware loop",
|
||||
@@ -252,9 +267,9 @@
|
||||
"evidence": "16666 browser, 16667/health, 16667/health/live, frps 7000, and tunnel health 7402 are reachable"
|
||||
},
|
||||
{
|
||||
"category": "other",
|
||||
"status": "not_observed",
|
||||
"evidence": "No additional blocker class observed in the short DEV-only retest"
|
||||
"category": "DB live",
|
||||
"status": "pass",
|
||||
"evidence": "Current d881a50 read-only M4 preflight evidence reports db.ready=true, db.connected=true, and liveDbEvidence=true; this does not clear runtime durability"
|
||||
}
|
||||
],
|
||||
"reportLifecycle": {
|
||||
|
||||
@@ -7,7 +7,7 @@ Scope: DEV only
|
||||
|
||||
## Summary
|
||||
|
||||
Public DEV route/frp is reachable on 16666/16667, but live MVP remains blocked by DB live readiness and the M3 hardware loop topology; no historical 6667 failure is counted as active evidence.
|
||||
Public DEV route/frp is reachable on 16666/16667, and current DB live evidence is ready, but live MVP remains blocked by runtime_durable_adapter_query_blocked, skills commit/version injection, and the M3 hardware loop topology; no historical 6667 failure is counted as active evidence.
|
||||
|
||||
## Commands
|
||||
|
||||
@@ -36,26 +36,28 @@ Public DEV route/frp is reachable on 16666/16667, but live MVP remains blocked b
|
||||
- `M1`: pass - The local M1 contract smoke passes.
|
||||
- `M2`: pass - The deploy smoke remains fixture-only and validates the frozen route phases and artifact metadata.
|
||||
- `M3`: blocked - Local M3 remains green, but active DEV-LIVE M3 is blocked by hardware loop topology.
|
||||
- `M4`: blocked - Local M4 remains green, but active DEV-LIVE M4 is blocked at DB live readiness before agent runtime scheduling.
|
||||
- `M5`: blocked - The M5 orchestration is green in dry-run mode, but active DEV-LIVE acceptance is blocked by DB live and hardware loop evidence.
|
||||
- `M4`: blocked - Local M4 remains green, but active DEV-LIVE M4 is blocked at runtime durable adapter readiness and skills commit/version injection before agent runtime scheduling.
|
||||
- `M5`: blocked - The M5 orchestration is green in dry-run mode, but active DEV-LIVE acceptance is blocked by runtime durable adapter, skills injection, and hardware loop evidence.
|
||||
|
||||
## Blocked Classification
|
||||
|
||||
| Category | Status | Evidence |
|
||||
| --- | --- | --- |
|
||||
| DB live | blocked | 16667/health/live serviceId=hwlab-cloud-api status=degraded db.ready=false db.connected=false |
|
||||
| agent runtime | not_run | M4 stopped before agent scheduling because DB live is blocked |
|
||||
| runtime durable adapter | blocked | runtime_durable_adapter_query_blocked; migration 0001_cloud_core_skeleton missing/not checked; db.liveDbEvidence=true is not durability evidence |
|
||||
| skills injection | blocked | hwlab-agent-skills has HWLAB_SKILLS_COMMIT_ID=d881a50 but no HWLAB_SKILLS_VERSION; agent manager health misses skillCommitId/skillVersion |
|
||||
| agent runtime | not_run | M4 stopped before agent scheduling because runtime durability and skills injection are blocked |
|
||||
| hardware loop | blocked | M3 stopped on missing patch-panel DO1 -> DI1 active connection |
|
||||
| evidence/audit | not_run | M3/M4 did not reach accepted hardware operations requiring audit/evidence closure |
|
||||
| CD apply | not_run | No deploy/apply command was run in this #64 retest |
|
||||
| frp | pass | 16666 browser, 16667/health, 16667/health/live, frps 7000, and tunnel health 7402 are reachable |
|
||||
| other | not_observed | No additional blocker class observed in the short DEV-only retest |
|
||||
| DB live | pass | Current d881a50 read-only M4 preflight evidence reports db.ready=true, db.connected=true, and liveDbEvidence=true; this does not clear runtime durability |
|
||||
|
||||
## Blockers
|
||||
|
||||
- DB live: cloud-api /health/live reports DB degraded; db.ready=false, db.connected=false, and live DB evidence is not established.
|
||||
- runtime durable adapter: cloud-api durable runtime adapter is blocked by runtime_durable_adapter_query_blocked; migration 0001_cloud_core_skeleton is missing or not checked.
|
||||
- skills injection: hwlab-agent-skills exposes HWLAB_SKILLS_COMMIT_ID=d881a50 but no HWLAB_SKILLS_VERSION; agent manager health misses skillCommitId/skillVersion.
|
||||
- hardware loop: Live M3 smoke reached DEV simulators, but patch-panel active DO1 -> DI1 connection is missing.
|
||||
|
||||
## Boundary
|
||||
|
||||
Active #64 DEV retest report. Public 16666/16667 route is reachable; live MVP remains blocked. No PROD, secret read, runtime restart, long-running agent task, or UniDesk runtime substitution was used.
|
||||
Active #64 DEV retest report. Public 16666/16667 route and DB live evidence are reachable; live MVP remains blocked. No PROD, secret read, runtime restart, long-running agent task, or UniDesk runtime substitution was used.
|
||||
|
||||
+128
-103
@@ -23,10 +23,12 @@ import { DEV_ENDPOINT, DEV_FRONTEND_ENDPOINT, ENVIRONMENT_DEV } from "../interna
|
||||
import {
|
||||
collectD601K3sNativeEvidence,
|
||||
collectPublicEntrypoints,
|
||||
classifyCloudApiLiveReadiness,
|
||||
d601K3sReadonlyCommand,
|
||||
d601Kubeconfig,
|
||||
devNamespace,
|
||||
requestJson,
|
||||
runtimeDurabilityFromHealth,
|
||||
workerServerDryRunCommand
|
||||
} from "./src/dev-m4-agent-loop-smoke-lib.mjs";
|
||||
|
||||
@@ -78,6 +80,14 @@ function statusForResult(result) {
|
||||
return result.blocked || (result.additionalBlockers?.length ?? 0) > 0 ? "blocked" : "pass";
|
||||
}
|
||||
|
||||
function dbLiveReadyForResult(result) {
|
||||
return result.dbLiveReady === true || (!result.blocked && result.dbLiveReady !== false);
|
||||
}
|
||||
|
||||
function runtimeDurableReadyForResult(result) {
|
||||
return result.runtimeDurableReady === true || (!result.blocked && result.runtimeDurableReady !== false);
|
||||
}
|
||||
|
||||
function blockerForResult(result) {
|
||||
const blockers = [];
|
||||
if (result.blocked && result.blockerType) {
|
||||
@@ -86,7 +96,8 @@ function blockerForResult(result) {
|
||||
scope: result.blockerScope ?? "devPreconditions",
|
||||
status: "open",
|
||||
summary: result.blockerSummary,
|
||||
classification: result.blockedClassification ?? "other"
|
||||
classification: result.blockedClassification ?? "other",
|
||||
...(result.sourceIssue ? { sourceIssue: result.sourceIssue } : {})
|
||||
});
|
||||
}
|
||||
for (const blocker of result.additionalBlockers ?? []) {
|
||||
@@ -119,11 +130,13 @@ function buildDryRunEvidence({ status = "not_run", details = [] } = {}) {
|
||||
}
|
||||
|
||||
function buildComponentEvidence(fixture, dryRun, result) {
|
||||
const dbLiveReady = dbLiveReadyForResult(result);
|
||||
const runtimeDurableReady = runtimeDurableReadyForResult(result);
|
||||
const dbLiveStatus = result.blockedClassification === "DB live"
|
||||
? "blocked"
|
||||
: result.blocked
|
||||
? "not_run"
|
||||
: "pass";
|
||||
: dbLiveReady
|
||||
? "pass"
|
||||
: "not_run";
|
||||
const m3DependencyStatus = result.blockedClassification === "hardware loop"
|
||||
? "blocked"
|
||||
: result.blocked
|
||||
@@ -164,11 +177,26 @@ function buildComponentEvidence(fixture, dryRun, result) {
|
||||
: "Trace/evidence/cleanup live closure was not attempted before preflight blockers were classified."
|
||||
},
|
||||
dbLive: {
|
||||
level: "BLOCKED",
|
||||
level: dbLiveStatus === "pass" ? "DEV-LIVE" : "BLOCKED",
|
||||
status: dbLiveStatus,
|
||||
summary: dbLiveStatus === "blocked"
|
||||
? "Live scheduling is stopped at cloud-api DB readiness; DB health is classified separately from local dry-run evidence."
|
||||
: "Live cloud-api DB readiness did not block before the current M4 classification point."
|
||||
: dbLiveStatus === "pass"
|
||||
? "Current read-only /health/live evidence reports DB ready=true, connected=true, and liveDbEvidence=true; DB live is not the active M4 blocker."
|
||||
: "Live cloud-api DB readiness did not block before the current M4 classification point."
|
||||
},
|
||||
runtimeDurableAdapter: {
|
||||
level: runtimeDurableReady ? "DEV-LIVE" : "BLOCKED",
|
||||
status: result.blockerScope === "runtime-durable-adapter"
|
||||
? "blocked"
|
||||
: runtimeDurableReady
|
||||
? "pass"
|
||||
: "not_run",
|
||||
summary: result.blockerScope === "runtime-durable-adapter"
|
||||
? "Live scheduling is stopped at runtime durable adapter readiness; DB live evidence alone is not runtime durability evidence."
|
||||
: runtimeDurableReady
|
||||
? "Current read-only /health/live evidence reports runtime.adapter=postgres, durable=true, ready=true, and liveRuntimeEvidence=true."
|
||||
: "Runtime durable adapter readiness did not produce the active M4 blocker."
|
||||
},
|
||||
m3HardwareLoopDependency: {
|
||||
level: "BLOCKED",
|
||||
@@ -182,12 +210,25 @@ function buildComponentEvidence(fixture, dryRun, result) {
|
||||
}
|
||||
|
||||
function buildDependencyState(result) {
|
||||
const dbLiveReady = dbLiveReadyForResult(result);
|
||||
const runtimeDurableReady = runtimeDurableReadyForResult(result);
|
||||
return {
|
||||
dbLive: {
|
||||
status: result.blockedClassification === "DB live" ? "blocked" : result.blocked ? "not_run" : "pass",
|
||||
status: result.blockedClassification === "DB live" ? "blocked" : dbLiveReady ? "pass" : "not_run",
|
||||
summary: result.blockedClassification === "DB live"
|
||||
? result.blockerSummary
|
||||
: "DB live readiness did not produce the active M4 blocker."
|
||||
: dbLiveReady
|
||||
? "cloud-api /health/live reports DB ready=true, connected=true, and liveDbEvidence=true."
|
||||
: "DB live readiness did not produce the active M4 blocker."
|
||||
},
|
||||
runtimeDurableAdapter: {
|
||||
status: result.blockerScope === "runtime-durable-adapter" ? "blocked" : runtimeDurableReady ? "pass" : "not_run",
|
||||
requiredEvidence: "Postgres runtime adapter schema, migration ledger, and read-query readiness with liveRuntimeEvidence=true.",
|
||||
summary: result.blockerScope === "runtime-durable-adapter"
|
||||
? result.blockerSummary
|
||||
: runtimeDurableReady
|
||||
? "cloud-api /health/live reports runtime.adapter=postgres, durable=true, ready=true, and liveRuntimeEvidence=true."
|
||||
: "Runtime durable adapter readiness did not produce the active M4 blocker."
|
||||
},
|
||||
m3HardwareLoop: {
|
||||
status: result.blockedClassification === "hardware loop" ? "blocked" : result.blocked ? "not_run" : "pass",
|
||||
@@ -284,6 +325,7 @@ function buildReport(
|
||||
`DEV browser route remains frozen at ${DEV_FRONTEND_ENDPOINT}`,
|
||||
`D601 native k3s access uses KUBECONFIG=${d601Kubeconfig} and namespace ${devNamespace}`,
|
||||
"No secret reads, real deployment, or long-running agent task is attempted",
|
||||
"DB live readiness and runtime durable adapter readiness are separate gates; DB live alone cannot promote M4",
|
||||
"Agent manager, worker, and skills are reachable only through the cloud API boundary",
|
||||
"M4 hardware assistance must go through cloud-api/hardware API and patch-panel; direct box/gateway access is forbidden"
|
||||
],
|
||||
@@ -416,105 +458,104 @@ async function runLivePreflight(fixture, dryRun) {
|
||||
blockerSummary: "DEV live probe did not present the expected HWLAB cloud API identity.",
|
||||
summary: "Blocked because the live DEV boundary did not expose the expected cloud API identity."
|
||||
};
|
||||
} else if (isDbLiveBlocked(liveBody)) {
|
||||
liveEvidence.push(`live:${liveBody.serviceId}:${liveBody.status}:db-blocked`);
|
||||
result = {
|
||||
blocked: true,
|
||||
blockerType: "runtime_blocker",
|
||||
blockerScope: "db-live",
|
||||
blockedClassification: "DB live",
|
||||
blockerSummary: summarizeDbBlocker(liveBody),
|
||||
summary: "Blocked at DB live readiness before scheduling a DEV agent task."
|
||||
};
|
||||
} else {
|
||||
liveEvidence.push(`live:${liveBody.serviceId}:${liveBody.status}`);
|
||||
|
||||
const rpcHealth = await requestJson(`${DEV_ENDPOINT}/rpc`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
jsonrpc: "2.0",
|
||||
id: "req_dev_m4_health",
|
||||
method: "system.health",
|
||||
params: {},
|
||||
meta: {
|
||||
traceId: "trc_dev_m4_health",
|
||||
serviceId: "hwlab-cli",
|
||||
environment: ENVIRONMENT_DEV
|
||||
}
|
||||
})
|
||||
});
|
||||
const rpcHealthBody = rpcHealth.body || {};
|
||||
liveEvidence.push(`rpc-health:${rpcHealthBody.result?.serviceId ?? "unknown"}`);
|
||||
if (rpcHealth.statusCode < 200 || rpcHealth.statusCode >= 300 || rpcHealthBody.error) {
|
||||
result = {
|
||||
blocked: true,
|
||||
blockerType: "agent_blocker",
|
||||
blockerScope: "agent-runtime",
|
||||
blockedClassification: "agent runtime",
|
||||
blockerSummary: rpcHealthBody.error?.message ?? `system.health returned HTTP ${rpcHealth.statusCode}.`,
|
||||
summary: "Blocked at agent runtime health before attempting hardware dispatch."
|
||||
};
|
||||
const liveReadiness = classifyCloudApiLiveReadiness(liveBody);
|
||||
if (liveReadiness.blocked) {
|
||||
liveEvidence.push(`live:${liveBody.serviceId}:${liveBody.status}:${liveReadiness.evidenceSuffix}`);
|
||||
const runtime = runtimeDurabilityFromHealth(liveBody);
|
||||
liveEvidence.push(`runtime-durable-adapter:adapter=${runtime.adapter}:blocker=${runtime.blocker}:migration=${runtime.migration.requiredMigrationId}:migrationChecked=${runtime.migration.checked}:migrationReady=${runtime.migration.ready}:queryResult=${runtime.queryResult}`);
|
||||
result = liveReadiness;
|
||||
} else {
|
||||
liveEvidence.push(`live:${liveBody.serviceId}:${liveBody.status}`);
|
||||
const runtime = runtimeDurabilityFromHealth(liveBody);
|
||||
liveEvidence.push(`runtime-durable-adapter:adapter=${runtime.adapter}:ready=${runtime.ready}:migration=${runtime.migration.requiredMigrationId}:queryResult=${runtime.queryResult}`);
|
||||
|
||||
const rpcHardware = await requestJson(`${DEV_ENDPOINT}/rpc`, {
|
||||
const rpcHealth = await requestJson(`${DEV_ENDPOINT}/rpc`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
jsonrpc: "2.0",
|
||||
id: "req_dev_m4_hw",
|
||||
method: "hardware.operation.request",
|
||||
params: {
|
||||
projectId: fixture.projectId,
|
||||
input: {
|
||||
requestedPath: "DO1 -> hwlab-patch-panel -> DI1",
|
||||
directBoxGatewayAccess: false,
|
||||
source: "dev-m4-agent-loop-preflight"
|
||||
}
|
||||
},
|
||||
id: "req_dev_m4_health",
|
||||
method: "system.health",
|
||||
params: {},
|
||||
meta: {
|
||||
traceId: "trc_dev_m4_hw",
|
||||
traceId: "trc_dev_m4_health",
|
||||
serviceId: "hwlab-cli",
|
||||
environment: ENVIRONMENT_DEV
|
||||
}
|
||||
})
|
||||
});
|
||||
const rpcHardwareBody = rpcHardware.body || {};
|
||||
const accepted = rpcHardwareBody.result?.accepted === true;
|
||||
const status = rpcHardwareBody.result?.status || rpcHardwareBody.error?.message || "unknown";
|
||||
liveEvidence.push(`rpc-hardware:${status}`);
|
||||
|
||||
if (!accepted) {
|
||||
const rpcHealthBody = rpcHealth.body || {};
|
||||
liveEvidence.push(`rpc-health:${rpcHealthBody.result?.serviceId ?? "unknown"}`);
|
||||
if (rpcHealth.statusCode < 200 || rpcHealth.statusCode >= 300 || rpcHealthBody.error) {
|
||||
result = {
|
||||
blocked: true,
|
||||
blockerType: "agent_blocker",
|
||||
blockerScope: "hardware-loop",
|
||||
blockedClassification: "hardware loop",
|
||||
blockerSummary: "hardware.operation.request did not accept the patch-panel-bounded M3 request.",
|
||||
summary: "Blocked by M3 readiness because M4 did not observe an accepted DO1 -> patch-panel -> DI1 hardware request."
|
||||
};
|
||||
} else if (!rpcHardwareBody.result?.auditId || !rpcHardwareBody.result?.evidenceId) {
|
||||
result = {
|
||||
blocked: true,
|
||||
blockerType: "observability_blocker",
|
||||
blockerScope: "evidence-audit",
|
||||
blockedClassification: "evidence/audit",
|
||||
blockerSummary: "hardware.operation.request accepted but did not return audit/evidence identifiers.",
|
||||
summary: "Blocked because accepted DEV agent hardware dispatch lacks audit/evidence closure."
|
||||
blockerScope: "agent-runtime",
|
||||
blockedClassification: "agent runtime",
|
||||
blockerSummary: rpcHealthBody.error?.message ?? `system.health returned HTTP ${rpcHealth.statusCode}.`,
|
||||
summary: "Blocked at agent runtime health before attempting hardware dispatch."
|
||||
};
|
||||
} else {
|
||||
result = {
|
||||
blocked: false,
|
||||
blockerType: null,
|
||||
blockerScope: null,
|
||||
blockedClassification: "none",
|
||||
blockerSummary: "",
|
||||
summary: "Live DEV preflight observed a non-skeleton agent hardware path."
|
||||
};
|
||||
const rpcHardware = await requestJson(`${DEV_ENDPOINT}/rpc`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
jsonrpc: "2.0",
|
||||
id: "req_dev_m4_hw",
|
||||
method: "hardware.operation.request",
|
||||
params: {
|
||||
projectId: fixture.projectId,
|
||||
input: {
|
||||
requestedPath: "DO1 -> hwlab-patch-panel -> DI1",
|
||||
directBoxGatewayAccess: false,
|
||||
source: "dev-m4-agent-loop-preflight"
|
||||
}
|
||||
},
|
||||
meta: {
|
||||
traceId: "trc_dev_m4_hw",
|
||||
serviceId: "hwlab-cli",
|
||||
environment: ENVIRONMENT_DEV
|
||||
}
|
||||
})
|
||||
});
|
||||
const rpcHardwareBody = rpcHardware.body || {};
|
||||
const accepted = rpcHardwareBody.result?.accepted === true;
|
||||
const status = rpcHardwareBody.result?.status || rpcHardwareBody.error?.message || "unknown";
|
||||
liveEvidence.push(`rpc-hardware:${status}`);
|
||||
|
||||
if (!accepted) {
|
||||
result = {
|
||||
blocked: true,
|
||||
blockerType: "agent_blocker",
|
||||
blockerScope: "hardware-loop",
|
||||
blockedClassification: "hardware loop",
|
||||
blockerSummary: "hardware.operation.request did not accept the patch-panel-bounded M3 request.",
|
||||
summary: "Blocked by M3 readiness because M4 did not observe an accepted DO1 -> patch-panel -> DI1 hardware request."
|
||||
};
|
||||
} else if (!rpcHardwareBody.result?.auditId || !rpcHardwareBody.result?.evidenceId) {
|
||||
result = {
|
||||
blocked: true,
|
||||
blockerType: "observability_blocker",
|
||||
blockerScope: "evidence-audit",
|
||||
blockedClassification: "evidence/audit",
|
||||
blockerSummary: "hardware.operation.request accepted but did not return audit/evidence identifiers.",
|
||||
summary: "Blocked because accepted DEV agent hardware dispatch lacks audit/evidence closure."
|
||||
};
|
||||
} else {
|
||||
result = {
|
||||
blocked: false,
|
||||
blockerType: null,
|
||||
blockerScope: null,
|
||||
blockedClassification: "none",
|
||||
blockerSummary: "",
|
||||
summary: "Live DEV preflight observed a non-skeleton agent hardware path."
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -575,20 +616,4 @@ async function main() {
|
||||
await runLivePreflight(fixture, await runDryRun(fixture));
|
||||
}
|
||||
|
||||
function isDbLiveBlocked(body) {
|
||||
const db = body?.db;
|
||||
if (!db || typeof db !== "object") {
|
||||
return false;
|
||||
}
|
||||
return db.connected === false || db.ready === false || ["blocked", "degraded"].includes(db.status);
|
||||
}
|
||||
|
||||
function summarizeDbBlocker(body) {
|
||||
const db = body?.db ?? {};
|
||||
const missing = Array.isArray(db.missingEnv) && db.missingEnv.length > 0
|
||||
? ` missing ${db.missingEnv.join(", ")}`
|
||||
: "";
|
||||
return `cloud-api /health/live reports DB ${db.status ?? "not ready"}; connected=${db.connected ?? "unknown"}; ready=${db.ready ?? "unknown"}.${missing}`;
|
||||
}
|
||||
|
||||
await main();
|
||||
|
||||
@@ -68,7 +68,9 @@ assert.equal(liveBlocked.exitCode, 2);
|
||||
const liveBlockedJson = JSON.parse(liveBlocked.stderr);
|
||||
assert.equal(liveBlockedJson.code, "BLOCKED");
|
||||
assert.equal(liveBlockedJson.blockers[0].type, "runtime_blocker");
|
||||
assert.equal(liveBlockedJson.blockers[0].scope, "db-live");
|
||||
assert.equal(liveBlockedJson.blockers[0].scope, "runtime-durable-adapter");
|
||||
assert.match(liveBlockedJson.blockers[0].summary, /runtime_durable_adapter_query_blocked/);
|
||||
assert.ok(liveBlockedJson.blockers.some((blocker) => blocker.scope === "skills-commit-version-injection"));
|
||||
assert.ok(liveBlockedJson.blockers.some((blocker) => blocker.scope === "m3-hardware-loop-runtime"));
|
||||
|
||||
assert.equal(gateSummary.endpoint, summary.endpoint);
|
||||
|
||||
@@ -5,6 +5,12 @@ import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import { activeReportLifecycle, reportIsHistorical, reportLifecycleState } from "../../internal/dev-report-lifecycle.mjs";
|
||||
import {
|
||||
RUNTIME_DURABLE_ADAPTER_MISSING,
|
||||
RUNTIME_DURABILITY_REQUIRED_EVIDENCE,
|
||||
RUNTIME_STORE_KIND_POSTGRES
|
||||
} from "../../internal/db/runtime-store.mjs";
|
||||
import { CLOUD_CORE_MIGRATION_ID } from "../../internal/db/schema.mjs";
|
||||
import { DEV_ENDPOINT, DEV_FRONTEND_ENDPOINT, ENVIRONMENT_DEV, SERVICE_IDS } from "../../internal/protocol/index.mjs";
|
||||
|
||||
export const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
@@ -189,7 +195,7 @@ function normalizeBlocker(blocker, sourceReport, fallbackPriority = "P3") {
|
||||
scope: blocker.scope,
|
||||
status: blocker.status ?? "open",
|
||||
source: sourceReport.path,
|
||||
sourceIssue: sourceReport.issue,
|
||||
sourceIssue: blocker.sourceIssue ?? sourceReport.issue,
|
||||
summary: oneLine(blocker.summary),
|
||||
...(nextTask ? { nextTask } : {})
|
||||
};
|
||||
@@ -198,7 +204,7 @@ function normalizeBlocker(blocker, sourceReport, fallbackPriority = "P3") {
|
||||
function dedupeBlockers(blockers) {
|
||||
const byKey = new Map();
|
||||
for (const blocker of blockers) {
|
||||
const key = `${blocker.type}:${blocker.scope}:${blocker.summary}`;
|
||||
const key = `${blocker.type}:${blocker.scope}`;
|
||||
const existing = byKey.get(key);
|
||||
if (!existing) {
|
||||
byKey.set(key, blocker);
|
||||
@@ -310,6 +316,26 @@ function applyPriority(blocker) {
|
||||
};
|
||||
}
|
||||
|
||||
if (blocker.scope === "runtime-durable-adapter") {
|
||||
return {
|
||||
...blocker,
|
||||
priority: "P1",
|
||||
unblockOrder: 5,
|
||||
unblocks: [issue(37), issue(39), issue(164)],
|
||||
rationale: "M4 and M5 cannot claim live agent or MVP evidence until the cloud-api postgres runtime adapter proves schema, migration, and read-query durability; DB live evidence alone is not durability evidence."
|
||||
};
|
||||
}
|
||||
|
||||
if (blocker.scope === "skills-commit-version-injection" || blocker.scope === "agent-mgr-health") {
|
||||
return {
|
||||
...blocker,
|
||||
priority: "P1",
|
||||
unblockOrder: 5,
|
||||
unblocks: [issue(37), issue(39), issue(164)],
|
||||
rationale: "M4/M5 agent evidence needs deployed manager, skills, and worker paths to expose explicit skills commit and version; session-mode-only worker templates are not enough."
|
||||
};
|
||||
}
|
||||
|
||||
if (isEdgeOrFrpBlocker(blocker)) {
|
||||
return {
|
||||
...blocker,
|
||||
@@ -629,18 +655,27 @@ function collectBlockers(reports) {
|
||||
if (isStaleLegacyIngressBlocker(blocker, report, reports)) {
|
||||
continue;
|
||||
}
|
||||
if (isStaleReadinessBlocker(blocker, reports)) {
|
||||
continue;
|
||||
}
|
||||
blockers.push(normalizeBlocker(blocker, report));
|
||||
}
|
||||
for (const blocker of report.artifactPublish?.blockers ?? []) {
|
||||
if (isStaleLegacyIngressBlocker(blocker, report, reports)) {
|
||||
continue;
|
||||
}
|
||||
if (isStaleReadinessBlocker(blocker, reports)) {
|
||||
continue;
|
||||
}
|
||||
blockers.push(normalizeBlocker(blocker, report));
|
||||
}
|
||||
for (const blocker of report.devDeployApply?.remainingBlockers ?? []) {
|
||||
if (isStaleLegacyIngressBlocker(blocker, report, reports)) {
|
||||
continue;
|
||||
}
|
||||
if (isStaleReadinessBlocker(blocker, reports)) {
|
||||
continue;
|
||||
}
|
||||
blockers.push(normalizeBlocker(blocker, report));
|
||||
}
|
||||
}
|
||||
@@ -722,6 +757,29 @@ function isStaleLegacyIngressBlocker(blocker, sourceReport, reports) {
|
||||
sourceReport.path !== reportPaths.devM5Gate;
|
||||
}
|
||||
|
||||
function isStaleReadinessBlocker(blocker, reports) {
|
||||
const scope = blocker.scope ?? "";
|
||||
const db = cloudApiDbStatus(reports);
|
||||
const provider = codeAgentProviderStatus(reports);
|
||||
if (
|
||||
(
|
||||
scope === "cloud-api-db" ||
|
||||
scope === "cloud-api-db-health-gate" ||
|
||||
scope === "cloud-api-db-live" ||
|
||||
scope === "db-live"
|
||||
) &&
|
||||
db.ready &&
|
||||
db.connected &&
|
||||
db.liveDbEvidence
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if ((scope === "code-agent-provider-secret" || scope === "code-agent-provider") && provider.ready) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function deriveMilestones(evidence, blockers) {
|
||||
const evidenceByMilestone = new Map();
|
||||
for (const item of evidence) {
|
||||
@@ -786,7 +844,7 @@ function buildMilestoneLevelClassification(milestones) {
|
||||
M1: "Local smoke is green; it is not DEV-LIVE.",
|
||||
M2: "Current public frontend/API route evidence is DEV-LIVE for route/front-end reachability only.",
|
||||
M3: "DEV-LIVE hardware trusted loop is blocked; local/source shape is not acceptance.",
|
||||
M4: "DEV-LIVE agent loop is blocked at DB live readiness; local smoke is not acceptance.",
|
||||
M4: "DEV-LIVE agent loop is blocked at runtime durable adapter or skills injection readiness; local smoke is not acceptance.",
|
||||
M5: "Dry-run is green, but bounded DEV-LIVE MVP e2e is blocked."
|
||||
};
|
||||
|
||||
@@ -918,6 +976,18 @@ function buildDoD(reports, milestones, blockers) {
|
||||
}
|
||||
|
||||
function cloudApiDbStatus(reports) {
|
||||
const liveDb = reports.devM4Agent.publicEntrypoints?.api?.live?.db ?? null;
|
||||
if (liveDb?.ready === true && liveDb?.connected === true && liveDb?.liveDbEvidence === true) {
|
||||
return {
|
||||
status: liveDb.status ?? "ok",
|
||||
ready: true,
|
||||
connected: true,
|
||||
configReady: liveDb.configReady === true,
|
||||
connectionChecked: liveDb.connectionChecked === true,
|
||||
endpointSource: liveDb.endpointSource ?? liveDb.connection?.endpointSource ?? "secret-url-host",
|
||||
liveDbEvidence: true
|
||||
};
|
||||
}
|
||||
const db = reports.devEdgeHealth.edgeHealth?.contracts?.deploy?.cloudApiDb ?? {};
|
||||
return {
|
||||
status: db.status ?? "unknown",
|
||||
@@ -930,10 +1000,91 @@ function cloudApiDbStatus(reports) {
|
||||
};
|
||||
}
|
||||
|
||||
function codeAgentProviderStatus(reports) {
|
||||
const codeAgent = reports.devM4Agent.publicEntrypoints?.api?.live?.codeAgent ??
|
||||
reports.devM4Agent.publicEntrypoints?.api?.health?.codeAgent ??
|
||||
null;
|
||||
return {
|
||||
ready: Boolean(codeAgent?.ready || codeAgent?.status === "ready" || codeAgent?.status === "available"),
|
||||
status: codeAgent?.status ?? "unknown",
|
||||
provider: codeAgent?.provider ?? "unknown"
|
||||
};
|
||||
}
|
||||
|
||||
function runtimeDurabilityStatusFromReport(report = {}) {
|
||||
const runtime = report.runtime ??
|
||||
report.livePreflight?.runtime ??
|
||||
report.publicEntrypoints?.api?.live?.runtime ??
|
||||
report.readiness?.durability ??
|
||||
{};
|
||||
const dependency = report.dependencyState?.runtimeDurableAdapter ?? {};
|
||||
const component = report.componentEvidence?.runtimeDurableAdapter ?? {};
|
||||
const blocker = report.blockers?.find((item) => item.scope === "runtime-durable-adapter") ?? null;
|
||||
const migration = runtime.migration ?? {};
|
||||
return {
|
||||
adapter: runtime.adapter ?? "unknown",
|
||||
durable: runtime.durable === true,
|
||||
durableRequested: Boolean(
|
||||
runtime.durableRequested ||
|
||||
runtime.adapter === RUNTIME_STORE_KIND_POSTGRES ||
|
||||
blocker ||
|
||||
dependency.status === "blocked" ||
|
||||
component.status === "blocked"
|
||||
),
|
||||
ready: Boolean(runtime.ready === true && runtime.liveRuntimeEvidence === true && runtime.durable === true),
|
||||
runtimeStatus: runtime.status ?? (blocker ? "blocked" : "unknown"),
|
||||
blocker: blocker?.classification ?? runtime.blocker ?? report.readiness?.durability?.blocker ?? RUNTIME_DURABLE_ADAPTER_MISSING,
|
||||
blockedLayer: runtime.durabilityContract?.blockedLayer ?? report.readiness?.durability?.blockedLayer ?? null,
|
||||
requiredEvidence: runtime.durabilityContract?.requiredEvidence ??
|
||||
report.readiness?.durability?.requiredEvidence ??
|
||||
RUNTIME_DURABILITY_REQUIRED_EVIDENCE,
|
||||
migration: {
|
||||
checked: migration.checked ?? null,
|
||||
ready: migration.ready ?? null,
|
||||
missing: migration.missing ?? null,
|
||||
requiredMigrationId: migration.requiredMigrationId ?? CLOUD_CORE_MIGRATION_ID,
|
||||
appliedMigrationId: migration.appliedMigrationId ?? null
|
||||
},
|
||||
queryAttempted: runtime.connection?.queryAttempted ?? null,
|
||||
queryResult: runtime.connection?.queryResult ?? "unknown",
|
||||
summary: blocker?.summary ?? dependency.summary ?? component.summary ?? "No runtime durable adapter evidence was attached."
|
||||
};
|
||||
}
|
||||
|
||||
function runtimeDurabilityStatus(reports) {
|
||||
return runtimeDurabilityStatusFromReport(reports.devM4Agent);
|
||||
}
|
||||
|
||||
function m4SkillsInjectionStatus(reports) {
|
||||
const native = reports.devM4Agent.d601K3sNative ?? {};
|
||||
const injection = native.skillsInjection ?? {};
|
||||
const blockers = reports.devM4Agent.blockers ?? [];
|
||||
const injectionBlocker = blockers.find((blocker) => blocker.scope === "skills-commit-version-injection") ?? null;
|
||||
const managerBlocker = blockers.find((blocker) => blocker.scope === "agent-mgr-health") ?? null;
|
||||
const missing = Array.isArray(injection.missing) ? injection.missing : [];
|
||||
const managerMissing = native.agentManager?.health?.missingSkills ?? [];
|
||||
return {
|
||||
status: injectionBlocker || managerBlocker || injection.status === "blocked" ? "blocked" : "pass",
|
||||
serviceCommitId: injection.serviceCommitId ?? null,
|
||||
serviceVersion: injection.serviceVersion ?? null,
|
||||
workerDryRunCommitId: injection.workerDryRunCommitId ?? null,
|
||||
workerDryRunVersion: injection.workerDryRunVersion ?? null,
|
||||
missing: [...new Set([...missing, ...managerMissing])],
|
||||
summary: injectionBlocker?.summary ??
|
||||
managerBlocker?.summary ??
|
||||
(injection.status === "blocked"
|
||||
? `DEV skills injection is incomplete: missing ${missing.join(", ")}.`
|
||||
: "DEV skills commit and version injection evidence is present.")
|
||||
};
|
||||
}
|
||||
|
||||
function buildCurrentDevLayering(reports, blockers) {
|
||||
const m2EndpointLive = hasCurrentM2EndpointEvidence(reports.devM2Smoke);
|
||||
const edgeLive = hasCurrentLiveEdgeEvidence(reports.devEdgeHealth);
|
||||
const cloudDb = cloudApiDbStatus(reports);
|
||||
const provider = codeAgentProviderStatus(reports);
|
||||
const runtimeDurability = runtimeDurabilityStatus(reports);
|
||||
const skillsInjection = m4SkillsInjectionStatus(reports);
|
||||
const dbReady = cloudDb.ready && cloudDb.connected && cloudDb.endpointSource === "secret-url-host" && cloudDb.liveDbEvidence;
|
||||
const m3Live = statusIsPass(reports.devM3Hardware.liveOperation?.status);
|
||||
const m4Live = statusIsPass(reports.devM4Agent.livePreflight?.status);
|
||||
@@ -971,6 +1122,41 @@ function buildCurrentDevLayering(reports, blockers) {
|
||||
evidence: reports.devM5Gate.devPreconditions?.evidence?.filter((line) => line.includes("/health/live") || line.includes("DB")) ?? [],
|
||||
nextRequired: "Provide live DB connection evidence through redacted health output; route reachability alone is insufficient."
|
||||
},
|
||||
runtimeDurableAdapter: {
|
||||
label: "Runtime durable adapter",
|
||||
status: runtimeDurability.ready ? "pass" : "blocked",
|
||||
evidenceLevel: runtimeDurability.ready ? "DEV-LIVE" : "BLOCKED",
|
||||
summary: `runtime adapter=${runtimeDurability.adapter}; durableRequested=${runtimeDurability.durableRequested}; durable=${runtimeDurability.durable}; ready=${runtimeDurability.ready}; blocker=${runtimeDurability.blocker}; migration=${runtimeDurability.migration.requiredMigrationId} checked=${runtimeDurability.migration.checked ?? "unknown"} ready=${runtimeDurability.migration.ready ?? "unknown"}; queryResult=${runtimeDurability.queryResult}.`,
|
||||
evidence: [
|
||||
`requiredEvidence=${runtimeDurability.requiredEvidence}`,
|
||||
`blockedLayer=${runtimeDurability.blockedLayer ?? "unknown"}`,
|
||||
`migration=${runtimeDurability.migration.requiredMigrationId}`,
|
||||
`queryAttempted=${runtimeDurability.queryAttempted ?? "unknown"}`
|
||||
],
|
||||
nextRequired: "Repair the postgres durable runtime adapter query/migration readiness and rerun health/M4 preflight without treating DB live as durability proof."
|
||||
},
|
||||
agentSkillsInjection: {
|
||||
label: "Agent skills injection",
|
||||
status: skillsInjection.status,
|
||||
evidenceLevel: skillsInjection.status === "pass" ? "DEV-LIVE" : "BLOCKED",
|
||||
summary: skillsInjection.summary,
|
||||
evidence: [
|
||||
`skills.commit=${skillsInjection.serviceCommitId ?? "missing"}`,
|
||||
`skills.version=${skillsInjection.serviceVersion ?? "missing"}`,
|
||||
`worker.commit=${skillsInjection.workerDryRunCommitId ?? "missing"}`,
|
||||
`worker.version=${skillsInjection.workerDryRunVersion ?? "missing"}`,
|
||||
`missing=${skillsInjection.missing.join(",") || "none"}`
|
||||
],
|
||||
nextRequired: "Inject explicit skill commit and version into hwlab-agent-mgr, hwlab-agent-skills, and scheduled worker jobs before claiming M4/M5 agent evidence."
|
||||
},
|
||||
codeAgentProvider: {
|
||||
label: "Code Agent provider",
|
||||
status: provider.ready ? "pass" : "blocked",
|
||||
evidenceLevel: provider.ready ? "DEV-LIVE" : "BLOCKED",
|
||||
summary: `code-agent provider=${provider.provider}; status=${provider.status}; ready=${provider.ready}.`,
|
||||
evidence: [`provider=${provider.provider}`, `status=${provider.status}`],
|
||||
nextRequired: "Keep provider-backed Code Agent readiness separate from DB live and runtime durable adapter readiness."
|
||||
},
|
||||
d601RunnerObservability: {
|
||||
label: "D601 runner observability",
|
||||
status: reports.d601Observability.runnerKubeconfigReadable === false
|
||||
@@ -1005,7 +1191,7 @@ function buildCurrentDevLayering(reports, blockers) {
|
||||
evidenceLevel: m4Live ? "DEV-LIVE" : "BLOCKED",
|
||||
summary: reports.devM4Agent.livePreflight?.summary ?? reports.devM4Agent.devPreconditions?.summary ?? "No live M4 observation was recorded.",
|
||||
evidence: reports.devM4Agent.livePreflight?.evidence ?? [],
|
||||
nextRequired: "Do not schedule or claim the agent loop as live until DB live and required runtime/evidence preconditions pass."
|
||||
nextRequired: "Do not schedule or claim the agent loop as live until DB live, runtime durable adapter, skills injection, and required evidence preconditions pass."
|
||||
},
|
||||
artifactDesiredStateSource: {
|
||||
label: "artifact/desired-state source",
|
||||
@@ -1024,6 +1210,8 @@ function buildCurrentDevLayering(reports, blockers) {
|
||||
|
||||
function buildMilestoneBlockerClassification(reports) {
|
||||
const cloudDb = cloudApiDbStatus(reports);
|
||||
const runtimeDurability = runtimeDurabilityStatus(reports);
|
||||
const skillsInjection = m4SkillsInjectionStatus(reports);
|
||||
const m3Live = statusIsPass(reports.devM3Hardware.liveOperation?.status);
|
||||
const m4Live = statusIsPass(reports.devM4Agent.livePreflight?.status);
|
||||
const m3ServiceDiscoveryBlocked = reports.devM3Hardware.blockers?.some((blocker) =>
|
||||
@@ -1045,6 +1233,23 @@ function buildMilestoneBlockerClassification(reports) {
|
||||
? "patch-panel-m3-wiring-missing"
|
||||
: "hardware-loop-runtime";
|
||||
|
||||
const m4RuntimeDurableBlocked = reports.devM4Agent.blockers?.some((blocker) =>
|
||||
blocker.scope === "runtime-durable-adapter"
|
||||
) === true || (!m4Live && runtimeDurability.durableRequested && !runtimeDurability.ready);
|
||||
const m4SkillsInjectionBlocked = skillsInjection.status === "blocked";
|
||||
const m4DbLiveBlocked = reports.devM4Agent.blockers?.some((blocker) =>
|
||||
blocker.scope === "db-live"
|
||||
) === true;
|
||||
const m4BlockerClass = m4Live
|
||||
? "cleared"
|
||||
: m4RuntimeDurableBlocked
|
||||
? runtimeDurability.blocker
|
||||
: m4SkillsInjectionBlocked
|
||||
? "skills-commit-version-injection"
|
||||
: m4DbLiveBlocked
|
||||
? "db-live-readiness"
|
||||
: "agent-loop-live-preflight";
|
||||
|
||||
return [
|
||||
{
|
||||
milestone: "M3",
|
||||
@@ -1083,31 +1288,51 @@ function buildMilestoneBlockerClassification(reports) {
|
||||
milestone: "M4",
|
||||
status: m4Live ? "pass" : "blocked",
|
||||
currentLevel: m4Live ? "DEV-LIVE" : "BLOCKED",
|
||||
blockerClass: m4Live ? "cleared" : "db-live-readiness",
|
||||
dependency: "Cloud API /health/live must report DB ready=true, connected=true, endpointSource=secret-url-host, and liveDbEvidence=true before live agent scheduling/evidence closure.",
|
||||
blockerClass: m4BlockerClass,
|
||||
dependency: m4RuntimeDurableBlocked
|
||||
? "Cloud API /health/live must prove the postgres durable runtime adapter schema, 0001_cloud_core_skeleton migration ledger, and read-query readiness before live agent scheduling/evidence closure."
|
||||
: m4SkillsInjectionBlocked
|
||||
? "Agent manager, skills service, and worker jobs must expose explicit skill commit and version fields before M4 live evidence can be trusted."
|
||||
: "Cloud API /health/live must report DB ready=true, connected=true, endpointSource=secret-url-host, and liveDbEvidence=true before live agent scheduling/evidence closure.",
|
||||
evidence: [
|
||||
`db.status=${cloudDb.status}`,
|
||||
`db.ready=${cloudDb.ready}`,
|
||||
`db.connected=${cloudDb.connected}`,
|
||||
`db.endpointSource=${cloudDb.endpointSource}`,
|
||||
`db.liveDbEvidence=${cloudDb.liveDbEvidence}`
|
||||
`db.liveDbEvidence=${cloudDb.liveDbEvidence}`,
|
||||
`runtime.adapter=${runtimeDurability.adapter}`,
|
||||
`runtime.blocker=${runtimeDurability.blocker}`,
|
||||
`runtime.migration=${runtimeDurability.migration.requiredMigrationId}`,
|
||||
`runtime.migration.ready=${runtimeDurability.migration.ready ?? "unknown"}`,
|
||||
`runtime.queryResult=${runtimeDurability.queryResult}`,
|
||||
`skills.missing=${skillsInjection.missing.join(",") || "none"}`
|
||||
],
|
||||
nextRequired: "Repair DB live readiness and rerun the M4 live preflight without scheduling a DEV agent task before preconditions pass.",
|
||||
nonPromotionReason: "Frontend revision and read-only route reachability do not prove DB-backed agent runtime readiness."
|
||||
nextRequired: m4RuntimeDurableBlocked
|
||||
? "Repair the runtime durable adapter query/migration readiness and rerun the M4 live preflight without scheduling a DEV agent task before preconditions pass."
|
||||
: m4SkillsInjectionBlocked
|
||||
? "Inject skill commit/version into agent manager, skills service, and worker jobs, then rerun the M4 read-only/live preflight."
|
||||
: "Repair DB live readiness and rerun the M4 live preflight without scheduling a DEV agent task before preconditions pass.",
|
||||
nonPromotionReason: "Frontend revision and read-only route reachability do not prove DB-backed durable agent runtime readiness or skill version injection."
|
||||
},
|
||||
{
|
||||
milestone: "M5",
|
||||
status: "blocked",
|
||||
currentLevel: "BLOCKED",
|
||||
blockerClass: "composite-db-m3-m4-live",
|
||||
dependency: "M5 needs DB live readiness, M3 trusted-loop DEV evidence, M4 live preflight/evidence closure, and current source/artifact coverage.",
|
||||
blockerClass: m4RuntimeDurableBlocked
|
||||
? "composite-runtime-durable-m3-m4-live"
|
||||
: m4SkillsInjectionBlocked
|
||||
? "composite-skills-injection-m3-m4-live"
|
||||
: "composite-db-m3-m4-live",
|
||||
dependency: "M5 needs DB live readiness, runtime durable adapter readiness, skills commit/version injection, M3 trusted-loop DEV evidence, M4 live preflight/evidence closure, and current source/artifact coverage.",
|
||||
evidence: [
|
||||
"M5 dry-run is green",
|
||||
`db.ready=${cloudDb.ready}`,
|
||||
`runtime.blocker=${runtimeDurability.blocker}`,
|
||||
`skills.status=${skillsInjection.status}`,
|
||||
`m3.live=${m3Live}`,
|
||||
`m4.live=${m4Live}`
|
||||
],
|
||||
nextRequired: "After DB/M3/M4 blockers are cleared, run only the bounded DEV MVP live gate command with explicit DEV/non-PROD confirmations.",
|
||||
nextRequired: "After DB/runtime durable adapter/skills/M3/M4 blockers are cleared, run only the bounded DEV MVP live gate command with explicit DEV/non-PROD confirmations.",
|
||||
nonPromotionReason: "No frontend, route-only, local, or dry-run evidence is allowed to stand in for bounded DEV-LIVE MVP e2e acceptance."
|
||||
}
|
||||
];
|
||||
@@ -1165,6 +1390,8 @@ function fallbackAction(scope) {
|
||||
if (scope.includes("edge") || scope.includes("ingress") || scope.includes("frp")) return "Repair frp/master-edge/D601 router path and rerun read-only DEV edge health.";
|
||||
if (scope.includes("cloud-api-db")) return "Configure DEV cloud-api DB env readiness and Secret URL host connectivity, then rerun health/preflight without exposing secrets.";
|
||||
if (scope === "db-live") return "Repair DEV cloud-api DB live readiness, then rerun the read-only health and M4 preflight reports without exposing secret values.";
|
||||
if (scope === "runtime-durable-adapter") return "Repair DEV cloud-api postgres durable runtime adapter schema/migration/read-query readiness, then rerun /health/live and the M4 preflight without exposing secret values.";
|
||||
if (scope === "skills-commit-version-injection" || scope === "agent-mgr-health") return "Inject explicit skills commit and version into agent manager, skills service, and worker jobs, then rerun the M4 read-only/live preflight.";
|
||||
if (scope === "m3-patch-panel-wiring") return "Load/apply DEV patch-panel wiring for res_boxsimu_1:DO1 -> res_boxsimu_2:DI1, then rerun the bounded DEV M3 smoke.";
|
||||
if (scope === "m3-box-simu-identity") return "Fix DEV box-simu instance identity so direct endpoints expose distinct res_boxsimu_1 and res_boxsimu_2 resources.";
|
||||
if (scope === "m3-gateway-simu-identity") return "Fix DEV gateway-simu instance identity so direct endpoints expose two distinct gateway sessions.";
|
||||
@@ -1181,6 +1408,8 @@ function evidenceRequiredFor(scope) {
|
||||
if (scope.includes("kubectl") || scope.includes("k3s")) return "Read-only kubectl/k3s report proving pods/services/configmaps are observable in hwlab-dev without reading Secrets.";
|
||||
if (scope.includes("cloud-api-db")) return "Cloud API health/live output showing DB env ready, endpointSource=secret-url-host, redacted secret references, and no secret material.";
|
||||
if (scope === "db-live") return "Cloud API /health/live output with ready=true, connected=true, endpointSource=secret-url-host, liveDbEvidence=true, and redacted secret references.";
|
||||
if (scope === "runtime-durable-adapter") return "Cloud API /health/live output with runtime.adapter=postgres, durable=true, ready=true, liveRuntimeEvidence=true, migration 0001_cloud_core_skeleton ready, and read-query readiness passing.";
|
||||
if (scope === "skills-commit-version-injection" || scope === "agent-mgr-health") return "Read-only hwlab-agent-mgr/hwlab-agent-skills health plus worker dry-run manifest showing skillCommitId/skillVersion and HWLAB_SKILL_COMMIT_ID/HWLAB_SKILL_VERSION injected.";
|
||||
if (scope === "m3-patch-panel-wiring") return "Read-only patch-panel /status and /wiring showing active res_boxsimu_1:DO1 -> res_boxsimu_2:DI1 before a bounded write/read smoke records operation, trace, audit, and evidence IDs.";
|
||||
if (scope === "m3-box-simu-identity") return "Read-only direct box-simu /health/live and /status output showing distinct res_boxsimu_1 and res_boxsimu_2 resources.";
|
||||
if (scope === "m3-gateway-simu-identity") return "Read-only direct gateway-simu /health/live and /status output showing two distinct gateway identities/sessions.";
|
||||
@@ -1299,7 +1528,7 @@ export async function buildReport() {
|
||||
green: dod.green,
|
||||
reason: dod.green
|
||||
? "All #9 DEV DoD checks are green."
|
||||
: `Frontend revision ${latestFrontendRevision} is usable in degraded/read-only mode and EDGE/ROUTE DEV-LIVE evidence exists on :16666/:16667, but M5 remains blocked by artifact source drift, API/runtime durability degradation, missing M3 trusted loop operation evidence, and blocked M4 agent-loop preflight.`
|
||||
: `Frontend revision ${latestFrontendRevision} is usable in degraded/read-only mode and EDGE/ROUTE DEV-LIVE evidence exists on :16666/:16667, but M5 remains blocked by artifact source drift, runtime durable adapter or skills injection readiness, missing M3 trusted loop operation evidence, and blocked M4 agent-loop preflight.`
|
||||
},
|
||||
latestFrontendDevFact: {
|
||||
...frontendDevFact,
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import { buildReport } from "./dev-evidence-blocker-aggregator.mjs";
|
||||
|
||||
test("aggregator reports M4 current blocker as durable runtime or skills injection, not stale DB live", async () => {
|
||||
const report = await buildReport();
|
||||
const m4 = report.milestoneBlockerClassification.find((item) => item.milestone === "M4");
|
||||
const m5 = report.milestoneBlockerClassification.find((item) => item.milestone === "M5");
|
||||
const dbLayer = report.currentDevLayering.dbLive;
|
||||
const dbCheck = report.dod.checks.find((item) => item.id === "cloud-api-db-ready");
|
||||
|
||||
assert.ok(m4, "M4 blocker classification is present");
|
||||
assert.ok(m5, "M5 blocker classification is present");
|
||||
assert.equal(dbLayer.status, "pass");
|
||||
assert.equal(dbLayer.evidenceLevel, "DEV-LIVE");
|
||||
assert.equal(dbCheck.status, "pass");
|
||||
assert.equal(dbCheck.evidenceLevel, "DEV-LIVE");
|
||||
assert.equal(
|
||||
report.blockers.some((blocker) =>
|
||||
["cloud-api-db", "cloud-api-db-health-gate", "cloud-api-db-live", "db-live"].includes(blocker.scope)
|
||||
),
|
||||
false,
|
||||
"DB live blockers must be stale once current DB live evidence is pass"
|
||||
);
|
||||
assert.notEqual(m4.blockerClass, "db-live-readiness");
|
||||
assert.ok(
|
||||
["runtime_durable_adapter_query_blocked", "skills-commit-version-injection"].includes(m4.blockerClass),
|
||||
`unexpected M4 blocker class ${m4.blockerClass}`
|
||||
);
|
||||
assert.match(m4.dependency, /durable runtime adapter|skill commit and version/u);
|
||||
assert.match(m4.nonPromotionReason, /durable agent runtime readiness|skill version injection/u);
|
||||
assert.match(m5.dependency, /runtime durable adapter readiness, skills commit\/version injection/u);
|
||||
});
|
||||
@@ -9,6 +9,12 @@ import {
|
||||
AGENT_SKILLS_SERVICE_ID,
|
||||
AGENT_WORKER_SERVICE_ID
|
||||
} from "../../internal/agent/index.mjs";
|
||||
import {
|
||||
RUNTIME_DURABLE_ADAPTER_MISSING,
|
||||
RUNTIME_DURABILITY_REQUIRED_EVIDENCE,
|
||||
RUNTIME_STORE_KIND_POSTGRES
|
||||
} from "../../internal/db/runtime-store.mjs";
|
||||
import { CLOUD_CORE_MIGRATION_ID } from "../../internal/db/schema.mjs";
|
||||
import { DEV_ENDPOINT, DEV_FRONTEND_ENDPOINT, ENVIRONMENT_DEV } from "../../internal/protocol/index.mjs";
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
@@ -20,6 +26,183 @@ export const d601K3sReadonlyCommand =
|
||||
export const workerServerDryRunCommand =
|
||||
"KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n hwlab-dev create -f - --dry-run=server -o json";
|
||||
|
||||
export function isDbLiveReady(body) {
|
||||
const db = body?.db;
|
||||
return Boolean(db?.ready && db?.connected && db?.liveConnected !== false && db?.liveDbEvidence);
|
||||
}
|
||||
|
||||
export function isDbLiveBlocked(body) {
|
||||
const db = body?.db;
|
||||
if (!db || typeof db !== "object") {
|
||||
return false;
|
||||
}
|
||||
if (isDbLiveReady(body)) {
|
||||
return false;
|
||||
}
|
||||
return db.connected === false ||
|
||||
db.ready === false ||
|
||||
db.liveConnected === false ||
|
||||
db.liveDbEvidence === false ||
|
||||
["blocked", "degraded", "failed"].includes(db.status);
|
||||
}
|
||||
|
||||
export function summarizeDbBlocker(body) {
|
||||
const db = body?.db ?? {};
|
||||
const missing = Array.isArray(db.missingEnv) && db.missingEnv.length > 0
|
||||
? ` missing ${db.missingEnv.join(", ")}`
|
||||
: "";
|
||||
return `cloud-api /health/live reports DB ${db.status ?? "not ready"}; connected=${db.connected ?? "unknown"}; ready=${db.ready ?? "unknown"}; liveDbEvidence=${db.liveDbEvidence ?? "unknown"}.${missing}`;
|
||||
}
|
||||
|
||||
export function runtimeDurabilityFromHealth(body) {
|
||||
const runtime = body?.runtime ?? {};
|
||||
const durability = body?.readiness?.durability ?? {};
|
||||
const migration = runtime.migration ?? {};
|
||||
const migrationGate = runtime.gates?.migration ?? durability.gates?.migration ?? {};
|
||||
const blocker = runtime.blocker ??
|
||||
durability.blocker ??
|
||||
(Array.isArray(body?.blockerCodes)
|
||||
? body.blockerCodes.find((code) => String(code).startsWith("runtime_durable_adapter_"))
|
||||
: null) ??
|
||||
RUNTIME_DURABLE_ADAPTER_MISSING;
|
||||
const durableRequested = Boolean(
|
||||
runtime.durableRequested ||
|
||||
durability.durableRequested ||
|
||||
runtime.adapter === RUNTIME_STORE_KIND_POSTGRES ||
|
||||
durability.adapter === RUNTIME_STORE_KIND_POSTGRES
|
||||
);
|
||||
const ready = Boolean(
|
||||
runtime.durable === true &&
|
||||
runtime.ready === true &&
|
||||
runtime.liveRuntimeEvidence === true &&
|
||||
durability.ready !== false
|
||||
);
|
||||
|
||||
return {
|
||||
adapter: runtime.adapter ?? durability.adapter ?? "unknown",
|
||||
durable: Boolean(runtime.durable),
|
||||
durableRequested,
|
||||
ready,
|
||||
runtimeStatus: runtime.status ?? durability.runtimeStatus ?? "unknown",
|
||||
blocker,
|
||||
blockedLayer: runtime.durabilityContract?.blockedLayer ?? durability.blockedLayer ?? null,
|
||||
requiredEvidence: runtime.durabilityContract?.requiredEvidence ??
|
||||
durability.requiredEvidence ??
|
||||
RUNTIME_DURABILITY_REQUIRED_EVIDENCE,
|
||||
migration: {
|
||||
checked: migration.checked ?? migrationGate.checked ?? false,
|
||||
ready: migration.ready ?? migrationGate.ready ?? false,
|
||||
missing: migration.missing ?? (migration.ready === false ? true : null),
|
||||
requiredMigrationId: migration.requiredMigrationId ?? CLOUD_CORE_MIGRATION_ID,
|
||||
appliedMigrationId: migration.appliedMigrationId ?? null
|
||||
},
|
||||
queryAttempted: Boolean(runtime.connection?.queryAttempted ?? durability.queryAttempted),
|
||||
queryResult: runtime.connection?.queryResult ?? durability.queryResult ?? "unknown"
|
||||
};
|
||||
}
|
||||
|
||||
export function isRuntimeDurableAdapterBlocked(body) {
|
||||
const runtime = runtimeDurabilityFromHealth(body);
|
||||
if (!runtime.durableRequested) {
|
||||
return false;
|
||||
}
|
||||
return !runtime.ready ||
|
||||
["blocked", "degraded", "failed"].includes(runtime.runtimeStatus) ||
|
||||
String(runtime.blocker).startsWith("runtime_durable_adapter_");
|
||||
}
|
||||
|
||||
export function summarizeRuntimeDurableBlocker(body) {
|
||||
const runtime = runtimeDurabilityFromHealth(body);
|
||||
const migration = runtime.migration;
|
||||
return `cloud-api durable runtime adapter is blocked: ${runtime.blocker}; adapter=${runtime.adapter}; durable=${runtime.durable}; ready=${runtime.ready}; migration=${migration.requiredMigrationId} checked=${migration.checked} ready=${migration.ready} missing=${migration.missing ?? "unknown"}; queryResult=${runtime.queryResult}.`;
|
||||
}
|
||||
|
||||
export function publicDbLiveSummary(body) {
|
||||
const db = body?.db ?? null;
|
||||
if (!db || typeof db !== "object") {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
status: db.status ?? null,
|
||||
connected: db.connected ?? null,
|
||||
liveConnected: db.liveConnected ?? null,
|
||||
ready: db.ready ?? null,
|
||||
configReady: db.configReady ?? null,
|
||||
connectionChecked: db.connectionChecked ?? null,
|
||||
connectionAttempted: db.connectionAttempted ?? null,
|
||||
connectionResult: db.connectionResult ?? null,
|
||||
endpointSource: db.endpointSource ?? db.connection?.endpointSource ?? null,
|
||||
liveDbEvidence: db.liveDbEvidence ?? null,
|
||||
evidence: db.evidence ?? null
|
||||
};
|
||||
}
|
||||
|
||||
export function publicRuntimeDurabilitySummary(body) {
|
||||
if (!body?.runtime && !body?.readiness?.durability) {
|
||||
return null;
|
||||
}
|
||||
const runtime = runtimeDurabilityFromHealth(body);
|
||||
return {
|
||||
adapter: runtime.adapter,
|
||||
durable: runtime.durable,
|
||||
durableRequested: runtime.durableRequested,
|
||||
ready: runtime.ready,
|
||||
status: runtime.runtimeStatus,
|
||||
blocker: runtime.blocker,
|
||||
blockedLayer: runtime.blockedLayer,
|
||||
requiredEvidence: runtime.requiredEvidence,
|
||||
liveRuntimeEvidence: Boolean(runtime.ready),
|
||||
migration: runtime.migration,
|
||||
queryAttempted: runtime.queryAttempted,
|
||||
queryResult: runtime.queryResult
|
||||
};
|
||||
}
|
||||
|
||||
export function classifyCloudApiLiveReadiness(body) {
|
||||
if (isDbLiveBlocked(body)) {
|
||||
return {
|
||||
blocked: true,
|
||||
blockerType: "runtime_blocker",
|
||||
blockerScope: "db-live",
|
||||
sourceIssue: "pikasTech/HWLAB#49",
|
||||
blockedClassification: "DB live",
|
||||
blockerSummary: summarizeDbBlocker(body),
|
||||
summary: "Blocked at DB live readiness before scheduling a DEV agent task.",
|
||||
evidenceSuffix: "db-blocked",
|
||||
dbLiveReady: false,
|
||||
runtimeDurableReady: false
|
||||
};
|
||||
}
|
||||
|
||||
if (isRuntimeDurableAdapterBlocked(body)) {
|
||||
const runtime = runtimeDurabilityFromHealth(body);
|
||||
return {
|
||||
blocked: true,
|
||||
blockerType: "runtime_blocker",
|
||||
blockerScope: "runtime-durable-adapter",
|
||||
sourceIssue: "pikasTech/HWLAB#164",
|
||||
blockedClassification: runtime.blocker,
|
||||
blockerSummary: summarizeRuntimeDurableBlocker(body),
|
||||
summary: "Blocked at runtime durable adapter readiness before scheduling a DEV agent task.",
|
||||
evidenceSuffix: `runtime-durable-adapter-blocked:${runtime.blocker}`,
|
||||
dbLiveReady: isDbLiveReady(body),
|
||||
runtimeDurableReady: false
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
blocked: false,
|
||||
blockerType: null,
|
||||
blockerScope: null,
|
||||
blockedClassification: "none",
|
||||
blockerSummary: "",
|
||||
summary: "Live DEV preflight observed DB live and durable runtime adapter readiness.",
|
||||
evidenceSuffix: null,
|
||||
dbLiveReady: isDbLiveReady(body),
|
||||
runtimeDurableReady: true
|
||||
};
|
||||
}
|
||||
|
||||
export function requestJson(urlString, { method = "GET", headers = {}, body, timeoutMs = 5000 } = {}) {
|
||||
const url = new URL(urlString);
|
||||
const client = url.protocol === "https:" ? httpsRequest : httpRequest;
|
||||
@@ -348,12 +531,9 @@ export async function collectPublicEntrypoints() {
|
||||
serviceId: apiLive.body?.serviceId ?? null,
|
||||
environment: apiLive.body?.environment ?? null,
|
||||
status: apiLive.body?.status ?? null,
|
||||
db: apiLive.body?.db ? {
|
||||
status: apiLive.body.db.status ?? null,
|
||||
connected: apiLive.body.db.connected ?? null,
|
||||
ready: apiLive.body.db.ready ?? null,
|
||||
evidence: apiLive.body.db.evidence ?? null
|
||||
} : null,
|
||||
db: publicDbLiveSummary(apiLive.body),
|
||||
runtime: publicRuntimeDurabilitySummary(apiLive.body),
|
||||
blockerCodes: Array.isArray(apiLive.body?.blockerCodes) ? apiLive.body.blockerCodes : [],
|
||||
error: apiLive.error ?? null
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import {
|
||||
classifyCloudApiLiveReadiness,
|
||||
publicDbLiveSummary,
|
||||
publicRuntimeDurabilitySummary,
|
||||
runtimeDurabilityFromHealth
|
||||
} from "./dev-m4-agent-loop-smoke-lib.mjs";
|
||||
|
||||
test("M4 live readiness classifies durable adapter query blocker after DB live is ready", () => {
|
||||
const payload = {
|
||||
db: {
|
||||
ready: true,
|
||||
connected: true,
|
||||
liveConnected: true,
|
||||
liveDbEvidence: true,
|
||||
status: "ok"
|
||||
},
|
||||
runtime: {
|
||||
adapter: "postgres",
|
||||
durable: false,
|
||||
durableRequested: true,
|
||||
ready: false,
|
||||
status: "blocked",
|
||||
blocker: "runtime_durable_adapter_query_blocked",
|
||||
reason: "durable runtime read query is blocked",
|
||||
liveRuntimeEvidence: false,
|
||||
connection: {
|
||||
queryAttempted: true,
|
||||
queryResult: "query_blocked"
|
||||
},
|
||||
migration: {
|
||||
checked: true,
|
||||
ready: false,
|
||||
missing: true,
|
||||
requiredMigrationId: "0001_cloud_core_skeleton"
|
||||
}
|
||||
},
|
||||
readiness: {
|
||||
durability: {
|
||||
blockedLayer: "durability_query",
|
||||
requiredEvidence: "runtime_adapter_schema_migration_read_query"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const classification = classifyCloudApiLiveReadiness(payload);
|
||||
assert.equal(classification.blocked, true);
|
||||
assert.equal(classification.blockerScope, "runtime-durable-adapter");
|
||||
assert.equal(classification.blockedClassification, "runtime_durable_adapter_query_blocked");
|
||||
assert.match(classification.blockerSummary, /0001_cloud_core_skeleton/u);
|
||||
assert.match(classification.evidenceSuffix, /runtime_durable_adapter_query_blocked/u);
|
||||
|
||||
const runtime = runtimeDurabilityFromHealth(payload);
|
||||
assert.equal(runtime.blocker, "runtime_durable_adapter_query_blocked");
|
||||
assert.equal(runtime.migration.checked, true);
|
||||
assert.equal(runtime.migration.ready, false);
|
||||
assert.equal(runtime.queryResult, "query_blocked");
|
||||
});
|
||||
|
||||
test("M4 live readiness keeps DB live blocker when DB is not connected", () => {
|
||||
const classification = classifyCloudApiLiveReadiness({
|
||||
db: {
|
||||
ready: false,
|
||||
connected: false,
|
||||
liveDbEvidence: false,
|
||||
status: "degraded"
|
||||
},
|
||||
runtime: {
|
||||
adapter: "postgres",
|
||||
durableRequested: true,
|
||||
blocker: "runtime_durable_adapter_query_blocked"
|
||||
}
|
||||
});
|
||||
|
||||
assert.equal(classification.blockerScope, "db-live");
|
||||
assert.equal(classification.blockedClassification, "DB live");
|
||||
});
|
||||
|
||||
test("public DB live summary preserves DB pass fields apart from durable adapter blocker", () => {
|
||||
const summary = publicDbLiveSummary({
|
||||
db: {
|
||||
status: "ok",
|
||||
connected: true,
|
||||
liveConnected: true,
|
||||
ready: true,
|
||||
configReady: true,
|
||||
connectionChecked: true,
|
||||
endpointSource: "secret-url-host",
|
||||
liveDbEvidence: true,
|
||||
evidence: "live_db_tcp_connection_ready"
|
||||
},
|
||||
runtime: {
|
||||
adapter: "postgres",
|
||||
durable: false,
|
||||
ready: false,
|
||||
blocker: "runtime_durable_adapter_query_blocked"
|
||||
}
|
||||
});
|
||||
|
||||
assert.equal(summary.status, "ok");
|
||||
assert.equal(summary.connected, true);
|
||||
assert.equal(summary.liveConnected, true);
|
||||
assert.equal(summary.ready, true);
|
||||
assert.equal(summary.configReady, true);
|
||||
assert.equal(summary.connectionChecked, true);
|
||||
assert.equal(summary.endpointSource, "secret-url-host");
|
||||
assert.equal(summary.liveDbEvidence, true);
|
||||
assert.equal(summary.evidence, "live_db_tcp_connection_ready");
|
||||
});
|
||||
|
||||
test("public runtime durability summary preserves durable adapter fields separately from DB live", () => {
|
||||
const summary = publicRuntimeDurabilitySummary({
|
||||
db: {
|
||||
ready: true,
|
||||
connected: true,
|
||||
liveConnected: true,
|
||||
liveDbEvidence: true
|
||||
},
|
||||
runtime: {
|
||||
adapter: "postgres",
|
||||
durable: false,
|
||||
durableRequested: true,
|
||||
ready: false,
|
||||
status: "blocked",
|
||||
blocker: "runtime_durable_adapter_query_blocked",
|
||||
liveRuntimeEvidence: false,
|
||||
connection: {
|
||||
queryAttempted: true,
|
||||
queryResult: "query_blocked"
|
||||
},
|
||||
migration: {
|
||||
checked: false,
|
||||
ready: false,
|
||||
missing: true,
|
||||
requiredMigrationId: "0001_cloud_core_skeleton"
|
||||
},
|
||||
durabilityContract: {
|
||||
blockedLayer: "durability_query",
|
||||
requiredEvidence: "runtime_adapter_schema_migration_read_query"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
assert.equal(summary.adapter, "postgres");
|
||||
assert.equal(summary.durableRequested, true);
|
||||
assert.equal(summary.durable, false);
|
||||
assert.equal(summary.ready, false);
|
||||
assert.equal(summary.liveRuntimeEvidence, false);
|
||||
assert.equal(summary.blocker, "runtime_durable_adapter_query_blocked");
|
||||
assert.equal(summary.blockedLayer, "durability_query");
|
||||
assert.equal(summary.requiredEvidence, "runtime_adapter_schema_migration_read_query");
|
||||
assert.equal(summary.queryAttempted, true);
|
||||
assert.equal(summary.queryResult, "query_blocked");
|
||||
assert.equal(summary.migration.requiredMigrationId, "0001_cloud_core_skeleton");
|
||||
});
|
||||
@@ -528,6 +528,8 @@ test("accepts the current blocked M5 aggregator non-promotion contract", async (
|
||||
|
||||
test("rejects aggregator DB acceptance promoted from frontend route evidence", async () => {
|
||||
const report = cloneBaseAggregatorReport();
|
||||
const m4Source = report.sourceReports.devM4Agent;
|
||||
m4Source.path = "reports/dev-gate/dev-edge-health.json";
|
||||
const check = report.dod.checks.find((item) => item.id === "cloud-api-db-ready");
|
||||
Object.assign(check, {
|
||||
status: "pass",
|
||||
@@ -542,6 +544,24 @@ test("rejects aggregator DB acceptance promoted from frontend route evidence", a
|
||||
await assertRejected(report, /DB DEV-LIVE acceptance source reports/);
|
||||
});
|
||||
|
||||
test("rejects aggregator stale DB runtime-env blocker when DB live is pass", async () => {
|
||||
const report = cloneBaseAggregatorReport();
|
||||
report.blockers.push({
|
||||
id: "dev-gate-preflight:cloud-api-db-health-gate",
|
||||
priority: "P1",
|
||||
type: "runtime_blocker",
|
||||
scope: "cloud-api-db-health-gate",
|
||||
status: "open",
|
||||
source: "reports/dev-gate/dev-preflight-report.json",
|
||||
sourceIssue: "pikasTech/HWLAB#34",
|
||||
summary: "cloud-api DB runtime env is not ready; missing HWLAB_CLOUD_DB_URL, HWLAB_CLOUD_DB_SSL_MODE.",
|
||||
unblockOrder: 5,
|
||||
unblocks: ["pikasTech/HWLAB#34", "pikasTech/HWLAB#33", "pikasTech/HWLAB#39"],
|
||||
rationale: "Stale DB runtime-env blocker fixture."
|
||||
});
|
||||
await assertRejected(report, /stale DB live\/runtime-env blocker/);
|
||||
});
|
||||
|
||||
test("rejects aggregator M3 acceptance promoted from source evidence", async () => {
|
||||
const report = cloneBaseAggregatorReport();
|
||||
const sourceEvidence = report.evidence.find((item) =>
|
||||
|
||||
@@ -2468,9 +2468,14 @@ function observedLiveIdentifier(value) {
|
||||
|
||||
function aggregatorLiveStateFromSources(sources) {
|
||||
const cloudApiDb = sources.devEdgeHealth.edgeHealth?.contracts?.deploy?.cloudApiDb ?? {};
|
||||
const dbLive = cloudApiDb.ready === true &&
|
||||
const edgeDbLive = cloudApiDb.ready === true &&
|
||||
(cloudApiDb.connected === true || cloudApiDb.liveConnected === true) &&
|
||||
cloudApiDb.liveDbEvidence === true;
|
||||
const m4LiveDb = sources.devM4Agent.publicEntrypoints?.api?.live?.db ?? {};
|
||||
const m4DbLive = m4LiveDb.ready === true &&
|
||||
(m4LiveDb.connected === true || m4LiveDb.liveConnected === true) &&
|
||||
m4LiveDb.liveDbEvidence === true;
|
||||
const dbLive = edgeDbLive || m4DbLive;
|
||||
const m3Operation = sources.devM3Hardware.liveOperation ?? {};
|
||||
const m3Live = statusIsPass(m3Operation.status) &&
|
||||
["operationId", "traceId", "auditId", "evidenceId"].every((field) =>
|
||||
@@ -2547,11 +2552,37 @@ function assertProtectedAggregatorDevLiveEvidence(item, label, liveState, assume
|
||||
);
|
||||
}
|
||||
|
||||
function assertNoStaleDbRuntimeBlocker(report, label, liveState) {
|
||||
if (!liveState.dbLive) {
|
||||
return;
|
||||
}
|
||||
|
||||
const staleDbScopes = new Set([
|
||||
"cloud-api-db",
|
||||
"cloud-api-db-health-gate",
|
||||
"cloud-api-db-live",
|
||||
"db-live"
|
||||
]);
|
||||
const staleBlocker = report.blockers?.find((blocker) => staleDbScopes.has(blocker.scope));
|
||||
assert.equal(
|
||||
staleBlocker,
|
||||
undefined,
|
||||
`${label}.blockers must not keep stale DB live/runtime-env blocker ${staleBlocker?.scope ?? ""} when DB live evidence is pass`
|
||||
);
|
||||
|
||||
const dbCheck = findById(report.dod.checks, "cloud-api-db-ready");
|
||||
assertObject(dbCheck, `${label}.dod.checks.cloud-api-db-ready`);
|
||||
assert.equal(dbCheck.status, "pass", `${label}.dod.checks.cloud-api-db-ready.status must be pass when DB live evidence is proven`);
|
||||
assert.equal(dbCheck.evidenceLevel, "DEV-LIVE", `${label}.dod.checks.cloud-api-db-ready.evidenceLevel must be DEV-LIVE when DB live evidence is proven`);
|
||||
}
|
||||
|
||||
async function assertAggregatorNonPromotionBoundaries(report, label) {
|
||||
const sources = await readAggregatorSourceReports(report, label);
|
||||
const liveState = aggregatorLiveStateFromSources(sources);
|
||||
const anyProtectedLiveBlocked = !liveState.dbLive || !liveState.m3Live || !liveState.m4Live || !liveState.m5Live;
|
||||
|
||||
assertNoStaleDbRuntimeBlocker(report, label, liveState);
|
||||
|
||||
assertObject(report.latestFrontendDevFact, `${label}.latestFrontendDevFact`);
|
||||
assert.equal(
|
||||
report.latestFrontendDevFact.promotesM3M4M5,
|
||||
|
||||
@@ -67,13 +67,14 @@ export const gateSummary = {
|
||||
},
|
||||
"devPreconditions": {
|
||||
"status": "blocked",
|
||||
"classification": "DB live; hardware loop",
|
||||
"classification": "runtime durable adapter; skills injection; hardware loop",
|
||||
"requirements": [
|
||||
"http://74.48.78.17:16666/ returns the DEV browser entry",
|
||||
"http://74.48.78.17:16667/health returns HWLAB DEV edge JSON",
|
||||
"http://74.48.78.17:16667/health/live returns HWLAB cloud-api JSON with DB live readiness",
|
||||
"http://74.48.78.17:16667/health/live returns HWLAB cloud-api JSON with DB live readiness and runtime durability separated",
|
||||
"Runtime durable adapter proves postgres schema, migration 0001_cloud_core_skeleton, and read-query readiness before M4/M5 can promote",
|
||||
"Agent manager, skills service, and worker jobs expose explicit skill commit/version before M4/M5 can promote",
|
||||
"M3 hardware loop proves box-simu-1 DO1 -> box-simu-2 DI1 via patch-panel",
|
||||
"M4 agent runtime/evidence path is only attempted after DB live and M3 readiness are not blocked",
|
||||
"Keep the run DEV-only and avoid PROD, heavy e2e, secrets, restarts, or UniDesk substitution"
|
||||
],
|
||||
"commands": [
|
||||
@@ -85,20 +86,26 @@ export const gateSummary = {
|
||||
],
|
||||
"evidence": [
|
||||
"http://74.48.78.17:16666/ -> HTTP 200 text/html, title=HWLAB DEV MVP Gate",
|
||||
"http://74.48.78.17:16667/health -> HTTP 200 serviceId=hwlab-edge-proxy status=ok commit=cb35ada6860653b27269b0a57991184118cbf4b1",
|
||||
"http://74.48.78.17:16667/health/live -> HTTP 200 serviceId=hwlab-cloud-api status=degraded db.ready=false db.connected=false db.connectionChecked=false",
|
||||
"dev-edge-health active report -> blocked by DB live readiness, while public 16667 TCP/HTTP and frp control/tunnel health are reachable",
|
||||
"http://74.48.78.17:16667/health -> HTTP 200 serviceId=hwlab-edge-proxy status=ok commit=d881a50",
|
||||
"http://74.48.78.17:16667/health/live -> HTTP 200 serviceId=hwlab-cloud-api status=degraded db.ready=true db.connected=true db.liveDbEvidence=true runtime.blocker=runtime_durable_adapter_query_blocked runtime.migration=0001_cloud_core_skeleton",
|
||||
"dev-edge-health active report remains older DB-live evidence and is superseded for M4/M5 blocker naming by current d881a50 M4 preflight evidence",
|
||||
"dev-m3-hardware-loop active report -> blocked, classification=hardware loop, summary=patch-panel active DO1 -> DI1 connection missing",
|
||||
"dev-m4-agent-loop active report -> blocked, classification=DB live, summary=cloud-api /health/live reports DB degraded; connected=false; ready=false"
|
||||
"dev-m4-agent-loop active report -> blocked, classification=runtime_durable_adapter_query_blocked, summary=runtime durable adapter query/migration readiness is blocked; skills commit/version injection is incomplete"
|
||||
],
|
||||
"summary": "Public DEV route/frp is reachable on 16666/16667, but live MVP remains blocked by DB live readiness and the M3 hardware loop topology; no historical 6667 failure is counted as active evidence."
|
||||
"summary": "Public DEV route/frp is reachable on 16666/16667, but live MVP remains blocked by runtime_durable_adapter_query_blocked, skills commit/version injection, and the M3 hardware loop topology; no DB-live-only blocker is counted as current M4/M5 evidence."
|
||||
},
|
||||
"blockers": [
|
||||
{
|
||||
"type": "runtime_blocker",
|
||||
"scope": "db-live",
|
||||
"scope": "runtime-durable-adapter",
|
||||
"status": "open",
|
||||
"summary": "cloud-api /health/live reports DB degraded; db.ready=false, db.connected=false, and live DB evidence is not established."
|
||||
"summary": "cloud-api durable runtime adapter is blocked: runtime_durable_adapter_query_blocked; migration 0001_cloud_core_skeleton is missing or not checked."
|
||||
},
|
||||
{
|
||||
"type": "agent_blocker",
|
||||
"scope": "skills-commit-version-injection",
|
||||
"status": "open",
|
||||
"summary": "DEV skills injection is incomplete: hwlab-agent-skills exposes HWLAB_SKILLS_COMMIT_ID=d881a50 but no HWLAB_SKILLS_VERSION; worker template only exposes session mode unless commit/version are injected."
|
||||
},
|
||||
{
|
||||
"type": "runtime_blocker",
|
||||
@@ -141,14 +148,14 @@ export const gateSummary = {
|
||||
"status": "blocked",
|
||||
"commandCount": 2,
|
||||
"evidenceCount": 2,
|
||||
"summary": "Local M4 remains green, but active DEV-LIVE M4 is blocked at DB live readiness before agent runtime scheduling."
|
||||
"summary": "Local M4 remains green, but active DEV-LIVE M4 is blocked at runtime durable adapter readiness and skills commit/version injection before agent runtime scheduling."
|
||||
},
|
||||
{
|
||||
"id": "M5",
|
||||
"status": "blocked",
|
||||
"commandCount": 3,
|
||||
"evidenceCount": 4,
|
||||
"summary": "The M5 orchestration is green in dry-run mode, but active DEV-LIVE acceptance is blocked by DB live and hardware loop evidence."
|
||||
"summary": "The M5 orchestration is green in dry-run mode, but active DEV-LIVE acceptance is blocked by runtime durable adapter, skills injection, and hardware loop evidence."
|
||||
}
|
||||
],
|
||||
"artifactCount": 13,
|
||||
|
||||
Reference in New Issue
Block a user