From ab1156564056f2ad1bbcd75a40031815b2b3281d Mon Sep 17 00:00:00 2001 From: Lyon <88232613+pikasTech@users.noreply.github.com> Date: Fri, 22 May 2026 13:15:31 +0800 Subject: [PATCH] test: refresh HWLAB DEV live evidence Merge PR #71 after commander review. Rebaselines DEV live evidence to 16666/16667, removes stale edge/frp blocker classification, keeps DB live and M3 patch-panel runtime as real blockers. Complies with HWLAB #78 / DC-DCSN-P0-2026-003 by preserving DEV-LIVE evidence boundaries and not treating Gate/UI as MVP success. --- README.md | 5 +- docs/dev-gate-preflight.md | 4 +- internal/mvp-gate/summary.mjs | 4 +- reports/dev-gate/dev-edge-health.json | 26 +- reports/dev-gate/dev-m3-hardware-loop.json | 47 +- reports/dev-gate/dev-m4-agent-loop.json | 18 +- .../dev-gate/dev-m5-gate-aggregator-v2.json | 511 ++++++------------ reports/dev-gate/dev-m5-gate-aggregator-v2.md | 37 +- reports/dev-gate/dev-mvp-gate-report.json | 115 +++- reports/dev-gate/dev-mvp-gate-report.md | 49 +- scripts/dev-m3-hardware-loop-smoke.mjs | 8 +- scripts/dev-m4-agent-loop-smoke.mjs | 145 +++-- scripts/l6-cli-web-smoke.mjs | 4 +- scripts/m5-mvp-e2e-dry-run.mjs | 4 +- .../src/dev-evidence-blocker-aggregator.mjs | 77 ++- scripts/validate-dev-gate-report.mjs | 7 +- web/hwlab-cloud-web/gate-summary.mjs | 59 +- 17 files changed, 590 insertions(+), 530 deletions(-) diff --git a/README.md b/README.md index a3cf8df0..f60e1338 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,9 @@ entry points that later service implementations must follow. ## MVP Freeze - MVP scope is DEV only. -- DEV endpoint is fixed at `http://74.48.78.17:6667`. -- PROD endpoint `:6666` is reserved and is not an MVP acceptance target. +- DEV browser/frontend endpoint is fixed at `http://74.48.78.17:16666/`. +- DEV API/edge/live endpoint is fixed at `http://74.48.78.17:16667`. +- PROD is not an MVP acceptance target. - UniDesk may be used only as an external scheduling, CI, or CD base. - HWLAB runtime services must not be replaced by UniDesk backend, provider-gateway, or microservice proxy implementations. diff --git a/docs/dev-gate-preflight.md b/docs/dev-gate-preflight.md index 5018c2ac..0ee495b2 100644 --- a/docs/dev-gate-preflight.md +++ b/docs/dev-gate-preflight.md @@ -60,8 +60,8 @@ The preflight checks: `HWLAB_CLOUD_DB_SSL_MODE=require`. - The local cloud-api health payload reports DB env presence/missing status with redacted values only. This is a readiness gate, not live DB evidence. -- `deploy/frp` and `deploy/master-edge` describe the D601-to-master DEV route - on port `6667`. +- `deploy/frp` and `deploy/master-edge` describe the D601-to-master DEV routes + on public ports `16666`/`16667`. - The runner can perform read-only `kubectl` probes against `hwlab-dev`. - `reports/dev-gate/dev-edge-health.json`, when present, records read-only public edge, frps, tunnel-health, and k3s observability evidence. diff --git a/internal/mvp-gate/summary.mjs b/internal/mvp-gate/summary.mjs index 3ce06e17..5c57109f 100644 --- a/internal/mvp-gate/summary.mjs +++ b/internal/mvp-gate/summary.mjs @@ -1,7 +1,9 @@ import fs from "node:fs"; import path from "node:path"; -export const DEV_ENDPOINT = "http://74.48.78.17:16667"; +import { DEV_ENDPOINT } from "../protocol/index.mjs"; + +export { DEV_ENDPOINT }; export const DEFAULT_GATE_REPORT_PATH = "reports/dev-gate/dev-mvp-gate-report.json"; export const DEFAULT_M5_PLAN_PATH = "fixtures/mvp/m5-e2e/dry-run-plan.json"; diff --git a/reports/dev-gate/dev-edge-health.json b/reports/dev-gate/dev-edge-health.json index a430972e..c6dff262 100644 --- a/reports/dev-gate/dev-edge-health.json +++ b/reports/dev-gate/dev-edge-health.json @@ -4,12 +4,12 @@ "reportVersion": "v1", "issue": "pikasTech/HWLAB#36", "taskId": "dev-edge-health", - "commitId": "cb35ada68606", + "commitId": "86d769525caf", "acceptanceLevel": "dev_edge_health", "devOnly": true, "prodDisabled": true, "status": "blocked", - "generatedAt": "2026-05-22T04:22:14.774Z", + "generatedAt": "2026-05-22T04:30:36.613Z", "namespace": "hwlab-dev", "endpoint": "http://74.48.78.17:16667", "sourceContract": { @@ -69,7 +69,7 @@ } ], "edgeHealth": { - "generatedAt": "2026-05-22T04:22:14.774Z", + "generatedAt": "2026-05-22T04:30:36.613Z", "mode": "live-read-only", "endpoint": "http://74.48.78.17:16667", "safety": { @@ -189,19 +189,19 @@ "host": "74.48.78.17", "port": 16667, "status": "connected", - "durationMs": 212 + "durationMs": 228 }, { "host": "74.48.78.17", "port": 7000, "status": "connected", - "durationMs": 1205 + "durationMs": 212 }, { "host": "74.48.78.17", "port": 7402, "status": "connected", - "durationMs": 232 + "durationMs": 216 } ], "publicHttp": [ @@ -214,7 +214,7 @@ "connection": "keep-alive", "content-length": "661", "content-type": "application/json; charset=utf-8", - "date": "Fri, 22 May 2026 04:22:14 GMT", + "date": "Fri, 22 May 2026 04:30:35 GMT", "keep-alive": "timeout=5" }, "json": { @@ -237,14 +237,14 @@ "digest": "unknown" }, "endpoint": "http://74.48.78.17:16667", - "observedAt": "2026-05-22T04:22:14.011Z", + "observedAt": "2026-05-22T04:30:35.063Z", "details": { "upstream": "http://hwlab-cloud-api.hwlab-dev.svc.cluster.local:6667", "mode": "dev-edge-proxy" } }, "bodyPreview": "{\n \"serviceId\": \"hwlab-edge-proxy\",\n \"environment\": \"dev\",\n \"status\": \"ok\",\n \"service\": {\n \"id\": \"hwlab-edge-proxy\",\n \"role\": \"public-dev-ingress\",\n \"healthPath\": \"/health\",\n \"livePath\": \"/health/live\"\n },\n \"commit\": {\n \"id\": \"cb35ada6860653b27269b0a57991184118cbf4b1\",\n \"source\": \"runtime-env\"\n },\n \"image\": {\n \"reference\": \"ghcr.io/pikastech/hwlab-edge-proxy:cb35ada\",\n \"tag\": \"cb35ada\",\n \"digest\": \"unknown\"\n },\n \"endpoint\": \"http://74.48.78.17:16667\",\n \"obse", - "durationMs": 821 + "durationMs": 2000 }, { "url": "http://74.48.78.17:16667/health/live", @@ -255,7 +255,7 @@ "cache-control": "no-store", "connection": "keep-alive", "content-type": "application/json; charset=utf-8", - "date": "Fri, 22 May 2026 04:22:14 GMT", + "date": "Fri, 22 May 2026 04:30:35 GMT", "keep-alive": "timeout=5", "transfer-encoding": "chunked" }, @@ -279,7 +279,7 @@ "digest": "unknown" }, "endpoint": "http://74.48.78.17:16667", - "observedAt": "2026-05-22T04:22:14.013Z", + "observedAt": "2026-05-22T04:30:35.064Z", "db": { "contractVersion": "v1", "environment": "dev", @@ -339,8 +339,8 @@ } } }, - "bodyPreview": "{\"serviceId\":\"hwlab-cloud-api\",\"environment\":\"dev\",\"status\":\"degraded\",\"service\":{\"id\":\"hwlab-cloud-api\",\"role\":\"cloud-api\",\"healthPath\":\"/health\",\"livePath\":\"/health/live\"},\"commit\":{\"id\":\"cb35ada\",\"source\":\"runtime-env\"},\"image\":{\"reference\":\"127.0.0.1:5000/hwlab/hwlab-cloud-api:cb35ada\",\"tag\":\"cb35ada\",\"digest\":\"unknown\"},\"endpoint\":\"http://74.48.78.17:16667\",\"observedAt\":\"2026-05-22T04:22:14.013Z\",\"db\":{\"contractVersion\":\"v1\",\"environment\":\"dev\",\"connected\":false,\"connectionChecked\":false,\"c", - "durationMs": 793 + "bodyPreview": "{\"serviceId\":\"hwlab-cloud-api\",\"environment\":\"dev\",\"status\":\"degraded\",\"service\":{\"id\":\"hwlab-cloud-api\",\"role\":\"cloud-api\",\"healthPath\":\"/health\",\"livePath\":\"/health/live\"},\"commit\":{\"id\":\"cb35ada\",\"source\":\"runtime-env\"},\"image\":{\"reference\":\"127.0.0.1:5000/hwlab/hwlab-cloud-api:cb35ada\",\"tag\":\"cb35ada\",\"digest\":\"unknown\"},\"endpoint\":\"http://74.48.78.17:16667\",\"observedAt\":\"2026-05-22T04:30:35.064Z\",\"db\":{\"contractVersion\":\"v1\",\"environment\":\"dev\",\"connected\":false,\"connectionChecked\":false,\"c", + "durationMs": 820 } ], "kubernetes": { diff --git a/reports/dev-gate/dev-m3-hardware-loop.json b/reports/dev-gate/dev-m3-hardware-loop.json index 69364ada..30ad366f 100644 --- a/reports/dev-gate/dev-m3-hardware-loop.json +++ b/reports/dev-gate/dev-m3-hardware-loop.json @@ -4,7 +4,7 @@ "reportVersion": "v1", "issue": "pikasTech/HWLAB#38", "taskId": "dev-m3-hardware-loop", - "commitId": "70bb9168ead2", + "commitId": "86d769525caf", "acceptanceLevel": "dev_m3_hardware_loop", "devOnly": true, "prodDisabled": true, @@ -64,20 +64,19 @@ }, { "id": "dev-ingress-health", - "status": "blocked", - "blockerClass": "network_blocker", - "summary": "DEV ingress at http://74.48.78.17:16667 did not return reachable HWLAB DEV health.", + "status": "pass", + "summary": "DEV ingress returned HWLAB identity at /health/live.", "evidence": [ - "{\"url\":\"http://74.48.78.17:16667/health/live\",\"method\":\"GET\",\"startedAt\":\"2026-05-21T17:29:33.794Z\",\"observedAt\":\"2026-05-21T17:29:33.964Z\",\"reached\":false,\"ok\":false,\"error\":{\"name\":\"Error\",\"message\":\"connect ECONNREFUSED 74.48.78.17:16667\",\"code\":\"ECONNREFUSED\"}}", - "{\"url\":\"http://74.48.78.17:16667/health\",\"method\":\"GET\",\"startedAt\":\"2026-05-21T17:29:33.964Z\",\"observedAt\":\"2026-05-21T17:29:34.132Z\",\"reached\":false,\"ok\":false,\"error\":{\"name\":\"Error\",\"message\":\"connect ECONNREFUSED 74.48.78.17:16667\",\"code\":\"ECONNREFUSED\"}}", - "{\"url\":\"http://74.48.78.17:16667/live\",\"method\":\"GET\",\"startedAt\":\"2026-05-21T17:29:34.132Z\",\"observedAt\":\"2026-05-21T17:29:34.313Z\",\"reached\":false,\"ok\":false,\"error\":{\"name\":\"Error\",\"message\":\"connect ECONNREFUSED 74.48.78.17:16667\",\"code\":\"ECONNREFUSED\"}}", - "{\"url\":\"http://74.48.78.17:16667/v1\",\"method\":\"GET\",\"startedAt\":\"2026-05-21T17:29:34.314Z\",\"observedAt\":\"2026-05-21T17:29:34.479Z\",\"reached\":false,\"ok\":false,\"error\":{\"name\":\"Error\",\"message\":\"connect ECONNREFUSED 74.48.78.17:16667\",\"code\":\"ECONNREFUSED\"}}" + "{\"url\":\"http://74.48.78.17:16667/health/live\",\"method\":\"GET\",\"startedAt\":\"2026-05-22T04:30:50.824Z\",\"observedAt\":\"2026-05-22T04:30:51.649Z\",\"reached\":true,\"ok\":true,\"status\":200,\"statusText\":\"OK\",\"json\":{\"serviceId\":\"hwlab-cloud-api\",\"environment\":\"dev\",\"status\":\"degraded\",\"service\":{\"id\":\"hwlab-cloud-api\",\"role\":\"cloud-api\",\"healthPath\":\"/health\",\"livePath\":\"/health/live\"},\"commit\":{\"id\":\"cb35ada\",\"source\":\"runtime-env\"},\"image\":{\"reference\":\"127.0.0.1:5000/hwlab/hwlab-cloud-api:cb35ada\",\"tag\":\"cb35ada\",\"digest\":\"unknown\"},\"endpoint\":\"http://74.48.78.17:16667\",\"observedAt\":\"2026-05-22T04:30:51.463Z\",\"db\":{\"contractVersion\":\"v1\",\"environment\":\"dev\",\"connected\":false,\"connectionChecked\":false,\"configReady\":true,\"ready\":false,\"status\":\"degraded\",\"mode\":\"configured_without_live_connection\",\"fields\":[{\"name\":\"HWLAB_CLOUD_DB_URL\",\"present\":true,\"redacted\":true,\"source\":\"k8s-secret-ref\",\"required\":true},{\"name\":\"HWLAB_CLOUD_DB_SSL_MODE\",\"present\":true,\"redacted\":false,\"source\":\"runtime-env\",\"required\":true}],\"missingEnv\":[],\"secretRefs\":[{\"env\":\"HWLAB_CLOUD_DB_URL\",\"secretName\":\"hwlab-cloud-api-dev-db\",\"secretKey\":\"database-url\",\"present\":true,\"redacted\":true}],\"safety\":{\"devOnly\":true,\"prodAllowed\":false,\"secretsRead\":false,\"valuesRedacted\":true,\"liveDbEvidence\":false},\"evidence\":\"env_presence_only_no_live_db\"},\"runtime\":{\"adapter\":\"memory\",\"durable\":false,\"status\":\"degraded\",\"reason\":\"live DB persistence is not connected; L1 runtime writes are process-local only\",\"counts\":{\"gatewaySessions\":0,\"boxResources\":0,\"boxCapabilities\":0,\"hardwareOperations\":0,\"auditEvents\":0,\"evidenceRecords\":0}}}}", + "{\"url\":\"http://74.48.78.17:16667/health\",\"method\":\"GET\",\"startedAt\":\"2026-05-22T04:30:51.650Z\",\"observedAt\":\"2026-05-22T04:30:52.025Z\",\"reached\":true,\"ok\":true,\"status\":200,\"statusText\":\"OK\",\"json\":{\"serviceId\":\"hwlab-edge-proxy\",\"environment\":\"dev\",\"status\":\"ok\",\"service\":{\"id\":\"hwlab-edge-proxy\",\"role\":\"public-dev-ingress\",\"healthPath\":\"/health\",\"livePath\":\"/health/live\"},\"commit\":{\"id\":\"cb35ada6860653b27269b0a57991184118cbf4b1\",\"source\":\"runtime-env\"},\"image\":{\"reference\":\"ghcr.io/pikastech/hwlab-edge-proxy:cb35ada\",\"tag\":\"cb35ada\",\"digest\":\"unknown\"},\"endpoint\":\"http://74.48.78.17:16667\",\"observedAt\":\"2026-05-22T04:30:51.840Z\",\"details\":{\"upstream\":\"http://hwlab-cloud-api.hwlab-dev.svc.cluster.local:6667\",\"mode\":\"dev-edge-proxy\"}}}", + "{\"url\":\"http://74.48.78.17:16667/live\",\"method\":\"GET\",\"startedAt\":\"2026-05-22T04:30:52.025Z\",\"observedAt\":\"2026-05-22T04:30:52.401Z\",\"reached\":true,\"ok\":true,\"status\":200,\"statusText\":\"OK\",\"json\":{\"serviceId\":\"hwlab-cloud-api\",\"status\":\"live\"}}", + "{\"url\":\"http://74.48.78.17:16667/v1\",\"method\":\"GET\",\"startedAt\":\"2026-05-22T04:30:52.401Z\",\"observedAt\":\"2026-05-22T04:30:53.001Z\",\"reached\":true,\"ok\":true,\"status\":200,\"statusText\":\"OK\",\"json\":{\"serviceId\":\"hwlab-cloud-api\",\"adapter\":\"rest\",\"status\":\"degraded\",\"rpcBridge\":\"POST /v1/rpc/{method}\",\"methods\":[\"system.health\",\"cloud.adapter.describe\",\"gateway.session.register\",\"box.resource.register\",\"box.capability.report\",\"hardware.operation.request\",\"hardware.invoke.shell\",\"audit.event.write\",\"audit.event.query\",\"evidence.record.write\",\"evidence.record.query\"],\"auditFields\":[\"requestId\",\"actor\",\"source\",\"operation\",\"target\",\"result\",\"timestamp\"],\"db\":{\"contractVersion\":\"v1\",\"environment\":\"dev\",\"connected\":false,\"connectionChecked\":false,\"configReady\":true,\"ready\":false,\"status\":\"degraded\",\"mode\":\"configured_without_live_connection\",\"fields\":[{\"name\":\"HWLAB_CLOUD_DB_URL\",\"present\":true,\"redacted\":true,\"source\":\"k8s-secret-ref\",\"required\":true},{\"name\":\"HWLAB_CLOUD_DB_SSL_MODE\",\"present\":true,\"redacted\":false,\"source\":\"runtime-env\",\"required\":true}],\"missingEnv\":[],\"secretRefs\":[{\"env\":\"HWLAB_CLOUD_DB_URL\",\"secretName\":\"hwlab-cloud-api-dev-db\",\"secretKey\":\"database-url\",\"present\":true,\"redacted\":true}],\"safety\":{\"devOnly\":true,\"prodAllowed\":false,\"secretsRead\":false,\"valuesRedacted\":true,\"liveDbEvidence\":false},\"evidence\":\"env_presence_only_no_live_db\"},\"runtime\":{\"adapter\":\"memory\",\"durable\":false,\"status\":\"degraded\",\"reason\":\"live DB persistence is not connected; L1 runtime writes are process-local only\",\"counts\":{\"gatewaySessions\":0,\"boxResources\":0,\"boxCapabilities\":0,\"hardwareOperations\":0,\"auditEvents\":0,\"evidenceRecords\":0}}}}" ] }, { "id": "two-box-simu-online", "status": "not_run", - "summary": "Stopped at DEV ingress per the DEV smoke matrix.", + "summary": "A live DEV M3 runtime contract check failed before all checks passed.", "evidence": [ "No live DEV evidence collected for this check." ] @@ -85,7 +84,7 @@ { "id": "two-gateway-simu-online", "status": "not_run", - "summary": "Stopped at DEV ingress per the DEV smoke matrix.", + "summary": "A live DEV M3 runtime contract check failed before all checks passed.", "evidence": [ "No live DEV evidence collected for this check." ] @@ -93,7 +92,7 @@ { "id": "patch-panel-healthy", "status": "not_run", - "summary": "Stopped at DEV ingress per the DEV smoke matrix.", + "summary": "A live DEV M3 runtime contract check failed before all checks passed.", "evidence": [ "No live DEV evidence collected for this check." ] @@ -101,7 +100,7 @@ { "id": "wiring-do1-di1-applied", "status": "not_run", - "summary": "Stopped at DEV ingress per the DEV smoke matrix.", + "summary": "A live DEV M3 runtime contract check failed before all checks passed.", "evidence": [ "No live DEV evidence collected for this check." ] @@ -109,7 +108,7 @@ { "id": "direct-call-do-write-di-read", "status": "not_run", - "summary": "Stopped at DEV ingress per the DEV smoke matrix.", + "summary": "A live DEV M3 runtime contract check failed before all checks passed.", "evidence": [ "No live DEV evidence collected for this check." ] @@ -117,7 +116,7 @@ { "id": "audit-evidence-traceable", "status": "not_run", - "summary": "Stopped at DEV ingress per the DEV smoke matrix.", + "summary": "A live DEV M3 runtime contract check failed before all checks passed.", "evidence": [ "No live DEV evidence collected for this check." ] @@ -169,9 +168,9 @@ }, { "id": "kubectl-hwlab-dev", - "status": "unavailable", - "command": "command -v kubectl", - "summary": "kubectl is not available in this runner, so hwlab-dev namespace state was not observed." + "status": "observed", + "command": "kubectl get deploy,po,svc -n hwlab-dev -o wide", + "summary": "NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR deployment.apps/hwlab-agent-mgr 1/1 1 1 4h38m hwlab-agent-mgr 127.0.0.1:5000/hwlab/hwlab-agent-mgr:cb35ada app.kubernetes.io/name=hwlab-agent-mgr,app.kubernetes.io/part-of=hwlab,hwlab.pikastech.local/environment=dev,hwlab.pikastech.local/profile=dev deployment.apps/hwlab-agent-skills 1/1 1 1 66m hwlab-agent-skills 127.0.0.1:5000/hwlab/hwlab-agent-skills:cb35ada app.kubernetes.io/name=hwlab-agent-skills,app.kubernetes.io/part-of=hwlab,hwlab.pikastech.local/environment=dev,hwlab.pikastech.local/profile=dev deployment.apps/hwlab-box-simu 2/2 2 2 4h38m hwlab-box-simu 127.0.0.1:5000/hwlab/hwlab-box-simu:cb35ada app.kubernetes.io/name=hwlab-box-simu,app.kubernetes.io/part-of=hwlab,hwlab.pikastech.local/environment=dev,hwlab.pikastech.local/profile=dev deployment.apps/hwlab-cloud-api 1/1 1 1 4h38m hwlab-cloud-api 127.0.0.1:5000/hwlab/hwlab-cloud-api:cb35ada app.kubernetes.io/name=hwlab-cloud-api,app.kubernetes.io/part-of=hwlab,hwlab.pikastech.local/environment=dev,hwlab.pikastech.local/profile=dev deployment.apps/hwlab-cloud-web 1/1 1 1 4h38m hwlab-cloud-web 127.0.0.1:5000/hwlab/hwlab-cloud-web:cb35ada app.kubernetes.io/name=hwlab-cloud-web,app.kubernetes.io/part-of=hwlab,hwlab.pikastech.local/environment=dev,hwlab.pikastech.local/profile=dev deployment.apps/hwlab-edge-proxy 1/1 1 1 4h38m hwlab-edge-proxy 127.0.0.1:5000/hwlab/hwlab-edge-proxy:cb35ada app.kubernetes.io/name=hwlab-edge-proxy,app.kubernetes.io/part-of=hwlab,hwlab.pikastech.local/environment=dev,hwlab.pikastech.local/profile=dev deployment.apps/hwlab-frpc 1/1 1 1 4h33m frpc 127.0.0.1:5000/hwlab/frpc:v0.68.1 app.kubernetes.io/name=hwlab-frpc deployment.apps/hwlab-gateway 0/0 0 0 4h38m hwlab-gateway 127.0.0.1:5000/hwlab/hwlab-gateway:cb35ada app.kubernetes.io/name=hwlab-gateway,app.kubernetes.io/part-of=hwlab,hwlab.pikastech.local/environment=dev,hwlab.pikastech.local/profile=dev deployment.apps/hwlab-gateway-simu 2/2 2 2 4h38m hwlab-gateway-simu 127.0.0.1:5000/hwlab/hwlab-gateway-simu:cb35ada app.kubernetes.io/name=hwlab-gateway-simu,app.kubernetes.io/part-of=hwlab,hwlab.pikastech.local/environment=dev,hwlab.pikastech.local/profile=dev deployment.apps/hwlab-patch-panel 1/1 1 1 4h38m hwlab-patch-panel 127.0.0.1:5000/hwlab/hwlab-patch-panel:cb35ada app.kubernetes.io/name=hwlab-patch-panel,app.kubernetes.io/part-of=hwlab,hwlab.pikastech.local/environment=dev,hwlab.pikastech.local/prof" } ], "liveOperation": { @@ -180,19 +179,21 @@ "traceId": "not_observed", "auditId": "not_observed", "evidenceId": "not_observed", - "summary": "No live do.write -> di.read operation was attempted because DEV ingress is blocked." + "summary": "No live DEV operation has run yet." }, "blockers": [ { - "type": "network_blocker", - "scope": "dev-ingress-health", + "type": "runtime_blocker", + "scope": "m3-hardware-loop-runtime", "status": "open", - "summary": "Blocked at the #33 DEV runtime readiness condition: public DEV ingress does not accept HWLAB health requests, so #36/M3 hardware-loop checks were not reached." + "classification": "hardware loop", + "summary": "patch-panel active DO1 -> DI1 connection missing" } ], "summary": { "status": "blocked", - "observedAt": "2026-05-21T17:29:33.789Z", - "result": "No live DEV M3 evidence was produced; fixture-backed local evidence was not used as a substitute." + "classification": "hardware loop", + "observedAt": "2026-05-22T04:30:50.820Z", + "result": "Live DEV M3 runtime was reachable but did not satisfy the M3 hardware-loop contract." } } diff --git a/reports/dev-gate/dev-m4-agent-loop.json b/reports/dev-gate/dev-m4-agent-loop.json index c59346f5..d0f094b4 100644 --- a/reports/dev-gate/dev-m4-agent-loop.json +++ b/reports/dev-gate/dev-m4-agent-loop.json @@ -4,7 +4,7 @@ "reportVersion": "v1", "issue": "pikasTech/HWLAB#37", "taskId": "dev-m4-agent-loop", - "commitId": "e9e71a7", + "commitId": "a1c3cb5", "acceptanceLevel": "dev_m4_agent_loop", "devOnly": true, "prodDisabled": true, @@ -46,30 +46,34 @@ }, "devPreconditions": { "status": "blocked", + "classification": "DB live", "requirements": [ "DEV route remains frozen at http://74.48.78.17:16667", "No secret reads, real deployment, or long-running agent task is attempted", "Agent manager, worker, and skills are reachable only through the cloud API boundary" ], - "summary": "Blocked before agent scheduling because http://74.48.78.17:16667 is unreachable from this runner." + "summary": "Blocked at DB live readiness before scheduling a DEV agent task." }, "blockers": [ { - "type": "network_blocker", - "scope": "devPreconditions", + "type": "runtime_blocker", + "scope": "db-live", "status": "open", - "summary": "connect ECONNREFUSED 74.48.78.17:16667" + "summary": "cloud-api /health/live reports DB degraded; connected=false; ready=false.", + "classification": "DB live" } ], "livePreflight": { "status": "blocked", + "classification": "DB live", "commands": [ "node scripts/dev-m4-agent-loop-smoke.mjs --live --confirm-dev --confirmed-non-production" ], "evidence": [ - "No live DEV observation was recorded." + "health:hwlab-edge-proxy:dev:ok", + "live:hwlab-cloud-api:degraded:db-blocked" ], - "summary": "Blocked before agent scheduling because http://74.48.78.17:16667 is unreachable from this runner." + "summary": "Blocked at DB live readiness before scheduling a DEV agent task." }, "notes": "DEV M4 agent loop live preflight report. No secret material is read." } diff --git a/reports/dev-gate/dev-m5-gate-aggregator-v2.json b/reports/dev-gate/dev-m5-gate-aggregator-v2.json index c9066757..82cd262f 100644 --- a/reports/dev-gate/dev-m5-gate-aggregator-v2.json +++ b/reports/dev-gate/dev-m5-gate-aggregator-v2.json @@ -17,8 +17,8 @@ "pikasTech/HWLAB#39", "pikasTech/HWLAB#46" ], - "generatedAt": "2026-05-21T18:27:07.237Z", - "generatedFromCommit": "1e9591a6611e", + "generatedAt": "2026-05-22T04:56:56.988Z", + "generatedFromCommit": "d4fe2cf1bb8a", "environment": "dev", "endpoint": "http://74.48.78.17:16667", "devOnly": true, @@ -45,43 +45,43 @@ "path": "reports/dev-gate/dev-deploy-report.json", "issue": "pikasTech/HWLAB#33", "taskId": "dev-deploy-apply", - "status": "blocked", - "commitId": "9b47ebe49f70" + "status": "pass", + "commitId": "73b379f4441d" }, "devArtifacts": { "path": "reports/dev-gate/dev-artifacts.json", "issue": "pikasTech/HWLAB#35", "taskId": "dev-artifact-publish", - "status": "blocked", - "commitId": "7e0ccb0" + "status": "published", + "commitId": "73b379f" }, "devEdgeHealth": { "path": "reports/dev-gate/dev-edge-health.json", "issue": "pikasTech/HWLAB#36", "taskId": "dev-edge-health", - "status": "not_run", - "commitId": "9b47ebe49f70" + "status": "blocked", + "commitId": "86d769525caf" }, "devM3Hardware": { "path": "reports/dev-gate/dev-m3-hardware-loop.json", "issue": "pikasTech/HWLAB#38", "taskId": "dev-m3-hardware-loop", "status": "blocked", - "commitId": "70bb9168ead2" + "commitId": "86d769525caf" }, "devM4Agent": { "path": "reports/dev-gate/dev-m4-agent-loop.json", "issue": "pikasTech/HWLAB#37", "taskId": "dev-m4-agent-loop", "status": "blocked", - "commitId": "e9e71a7" + "commitId": "a1c3cb5" }, "devM5Gate": { "path": "reports/dev-gate/dev-mvp-gate-report.json", "issue": "pikasTech/HWLAB#39", "taskId": "dev-mvp-gate-report", "status": "blocked", - "commitId": "6eb4c199b0c6" + "commitId": "86d769525caf" }, "d601Observability": { "path": "reports/d601-k3s-readonly-observability.json", @@ -94,7 +94,7 @@ "overall": { "status": "blocked", "green": false, - "reason": "SOURCE, LOCAL, and DRY-RUN evidence exists, but DEV-LIVE acceptance is blocked by artifact, observability, DB, edge/frp, and loop evidence gaps." + "reason": "SOURCE, LOCAL, DRY-RUN, and edge DEV-LIVE evidence exists, but acceptance is still blocked by artifact, observability, DB, and loop evidence gaps." }, "dod": { "status": "blocked", @@ -125,10 +125,10 @@ "summary": "D601 runner lacks kubectl/k3s/kubeconfig observability for hwlab-dev." }, { - "id": "dev-edge-frp-6667", - "status": "blocked", - "evidenceLevel": "BLOCKED", - "summary": "No committed report proves live HTTP 200/JSON on http://74.48.78.17:16667." + "id": "dev-edge-frp-16667", + "status": "pass", + "evidenceLevel": "DEV-LIVE", + "summary": "Committed edge report proves read-only public HTTP on :16667 /health and /health/live; old preflight network probe blockers are stale." }, { "id": "cloud-api-db-ready", @@ -166,11 +166,11 @@ { "id": "M2", "status": "blocked", - "highestVisibleLevel": "DRY-RUN", + "highestVisibleLevel": "DEV-LIVE", "liveEvidence": "missing_or_blocked", "evidenceCount": 5, - "blockerCount": 18, - "summary": "deploy/runtime readiness is blocked before live DEV; highest visible level is DRY-RUN; status is blocked." + "blockerCount": 9, + "summary": "deploy/runtime readiness is blocked before live DEV; highest visible level is DEV-LIVE; status is blocked." }, { "id": "M3", @@ -178,17 +178,17 @@ "highestVisibleLevel": "LOCAL", "liveEvidence": "missing_or_blocked", "evidenceCount": 3, - "blockerCount": 10, + "blockerCount": 4, "summary": "hardware loop has source/local shape but no live operation; highest visible level is LOCAL; status is blocked." }, { "id": "M4", - "status": "blocked", + "status": "not_run", "highestVisibleLevel": "LOCAL", "liveEvidence": "missing_or_blocked", "evidenceCount": 3, - "blockerCount": 5, - "summary": "agent loop has local smoke but live preflight is blocked; highest visible level is LOCAL; status is blocked." + "blockerCount": 0, + "summary": "agent loop has local smoke but live preflight is blocked; highest visible level is LOCAL; status is not_run." }, { "id": "M5", @@ -196,7 +196,7 @@ "highestVisibleLevel": "DRY-RUN", "liveEvidence": "missing_or_blocked", "evidenceCount": 2, - "blockerCount": 12, + "blockerCount": 9, "summary": "dry-run is green but live MVP gate is blocked; highest visible level is DRY-RUN; status is blocked." } ], @@ -266,9 +266,9 @@ "issue": "pikasTech/HWLAB#33", "taskId": "dev-deploy-apply", "reportPath": "reports/dev-gate/dev-deploy-report.json", - "commitId": "9b47ebe49f70", + "commitId": "73b379f4441d", "level": "DRY-RUN", - "status": "blocked", + "status": "pass", "category": "deploy-apply", "commands": [ "node tools/hwlab-cli/bin/hwlab-cli.mjs test e2e --env dev --mvp --dry-run", @@ -276,25 +276,26 @@ ], "evidence": [ "artifact services checked: 13", - "expected artifact commit: 24eb3bf", + "expected artifact commit: 73b379f", "namespace: hwlab-dev", "workloads planned: 13", - "kubectl executor: missing", - "live health: not_run" + "kubectl executor: /usr/local/bin/kubectl", + "live health: pass" ], - "summary": "DEV apply is blocked before mutation." + "summary": "DEV dry-run preflight passed." }, { "milestone": "M2", "issue": "pikasTech/HWLAB#35", "taskId": "dev-artifact-publish", "reportPath": "reports/dev-gate/dev-artifacts.json", - "commitId": "7e0ccb0", + "commitId": "73b379f", "level": "DRY-RUN", - "status": "blocked", + "status": "published", "category": "artifact-publish", "commands": [ "node --check scripts/dev-artifact-publish.mjs", + "node --check scripts/src/dev-artifact-services.mjs", "node --check scripts/preflight-dev-base-image.mjs", "node --check scripts/src/dev-base-image-preflight.mjs", "node scripts/preflight-dev-base-image.mjs", @@ -304,8 +305,8 @@ ], "evidence": [ "services=13", - "baseImagePreflight=blocked", - "published=0/13" + "baseImagePreflight=ready", + "published=13/13" ], "summary": "Artifact publish preflight exists but is blocked before any real image publish." }, @@ -314,9 +315,9 @@ "issue": "pikasTech/HWLAB#36", "taskId": "dev-edge-health", "reportPath": "reports/dev-gate/dev-edge-health.json", - "commitId": "9b47ebe49f70", - "level": "SOURCE", - "status": "not_run", + "commitId": "86d769525caf", + "level": "DEV-LIVE", + "status": "blocker", "category": "edge-frp-contract", "commands": [ "node --check scripts/validate-dev-gate-report.mjs", @@ -326,11 +327,11 @@ "node scripts/dev-edge-health-smoke.mjs --live --write-report" ], "evidence": [ - "mode=contract-only", - "classification=not_run", - "cloudApiDb=ready" + "mode=live-read-only", + "classification=app_health_blocker", + "cloudApiDb=degraded" ], - "summary": "Committed edge report is contract-only/not-run; it must not be counted as DEV-LIVE." + "summary": "Committed edge report proves read-only public HTTP on :16667 /health and /health/live; remaining edge report blocker is DB readiness, not route/frp reachability." }, { "milestone": "M2", @@ -358,7 +359,7 @@ "issue": "pikasTech/HWLAB#38", "taskId": "dev-m3-hardware-loop", "reportPath": "reports/dev-gate/dev-m3-hardware-loop.json", - "commitId": "70bb9168ead2", + "commitId": "86d769525caf", "level": "SOURCE", "status": "manifest-ready", "category": "hardware-loop-cardinality", @@ -375,26 +376,27 @@ "issue": "pikasTech/HWLAB#39", "taskId": "dev-mvp-gate-report", "reportPath": "reports/dev-gate/dev-mvp-gate-report.json", - "commitId": "6eb4c199b0c6", + "commitId": "86d769525caf", "level": "LOCAL", - "status": "pass", + "status": "blocked", "category": "hardware-loop-local", "commands": [ - "node scripts/m3-hardware-loop-smoke.mjs" + "node scripts/m3-hardware-loop-smoke.mjs", + "node scripts/dev-m3-hardware-loop-smoke.mjs --live --confirm-dev --confirmed-non-production" ], "evidence": [ - "M3 hardware loop smoke passed", - "topology: 2 box simulators, 2 gateway simulators, 1 patch panel", - "wiring: box-simu-1 DO1 -> box-simu-2 DI1 via hwlab-patch-panel" + "Local M3 hardware loop smoke passed", + "Live DEV M3 smoke reached 16667 ingress and direct simulator/patch-panel Pod URLs", + "Live DEV M3 blocked: patch-panel active DO1 -> DI1 connection missing" ], - "summary": "The local hardware trusted loop smoke passes." + "summary": "Local M3 remains green, but active DEV-LIVE M3 is blocked by hardware loop topology." }, { "milestone": "M3", "issue": "pikasTech/HWLAB#38", "taskId": "dev-m3-hardware-loop", "reportPath": "reports/dev-gate/dev-m3-hardware-loop.json", - "commitId": "70bb9168ead2", + "commitId": "86d769525caf", "level": "BLOCKED", "status": "not_run", "category": "hardware-loop-live", @@ -407,14 +409,14 @@ "auditId=not_observed", "evidenceId=not_observed" ], - "summary": "No live do.write -> di.read operation was attempted because DEV ingress is blocked." + "summary": "No live DEV operation has run yet." }, { "milestone": "M4", "issue": "pikasTech/HWLAB#37", "taskId": "dev-m4-agent-loop", "reportPath": "reports/dev-gate/dev-m4-agent-loop.json", - "commitId": "e9e71a7", + "commitId": "a1c3cb5", "level": "LOCAL", "status": "pass", "category": "agent-loop-local", @@ -432,7 +434,7 @@ "issue": "pikasTech/HWLAB#37", "taskId": "dev-m4-agent-loop", "reportPath": "reports/dev-gate/dev-m4-agent-loop.json", - "commitId": "e9e71a7", + "commitId": "a1c3cb5", "level": "DRY-RUN", "status": "not_run", "category": "agent-loop-dry-run", @@ -449,7 +451,7 @@ "issue": "pikasTech/HWLAB#37", "taskId": "dev-m4-agent-loop", "reportPath": "reports/dev-gate/dev-m4-agent-loop.json", - "commitId": "e9e71a7", + "commitId": "a1c3cb5", "level": "BLOCKED", "status": "blocked", "category": "agent-loop-live-preflight", @@ -457,16 +459,17 @@ "node scripts/dev-m4-agent-loop-smoke.mjs --live --confirm-dev --confirmed-non-production" ], "evidence": [ - "No live DEV observation was recorded." + "health:hwlab-edge-proxy:dev:ok", + "live:hwlab-cloud-api:degraded:db-blocked" ], - "summary": "Blocked before agent scheduling because http://74.48.78.17:16667 is unreachable from this runner." + "summary": "Blocked at DB live readiness before scheduling a DEV agent task." }, { "milestone": "M5", "issue": "pikasTech/HWLAB#39", "taskId": "dev-mvp-gate-report", "reportPath": "reports/dev-gate/dev-mvp-gate-report.json", - "commitId": "6eb4c199b0c6", + "commitId": "86d769525caf", "level": "DRY-RUN", "status": "pass", "category": "mvp-e2e-dry-run", @@ -487,19 +490,26 @@ "issue": "pikasTech/HWLAB#39", "taskId": "dev-mvp-gate-report", "reportPath": "reports/dev-gate/dev-mvp-gate-report.json", - "commitId": "6eb4c199b0c6", + "commitId": "86d769525caf", "level": "BLOCKED", "status": "blocked", "category": "mvp-e2e-live", "commands": [ - "curl -fsS --max-time 5 http://74.48.78.17:16667/health", - "curl -fsS --max-time 5 http://74.48.78.17:16667/live" + "curl -fsS --max-time 8 http://74.48.78.17:16666/", + "curl -fsS --max-time 8 http://74.48.78.17:16667/health/live", + "curl -fsS --max-time 8 http://74.48.78.17:16667/health", + "HWLAB_DEV_BOX_SIMU_1_URL=http://10.42.0.200:7201 HWLAB_DEV_BOX_SIMU_2_URL=http://10.42.0.208:7201 HWLAB_DEV_GATEWAY_SIMU_1_URL=http://10.42.0.209:7101 HWLAB_DEV_GATEWAY_SIMU_2_URL=http://10.42.0.204:7101 HWLAB_DEV_PATCH_PANEL_URL=http://10.42.0.205:7301 node scripts/dev-m3-hardware-loop-smoke.mjs --live --confirm-dev --confirmed-non-production", + "node scripts/dev-m4-agent-loop-smoke.mjs --live --confirm-dev --confirmed-non-production" ], "evidence": [ - "curl exit 7 for /health: could not connect to 74.48.78.17 port 6667", - "curl exit 7 for /live: could not connect to 74.48.78.17 port 6667" + "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", + "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" ], - "summary": "The frozen DEV endpoint is not reachable from this runner, so no live DEV gate can be claimed yet." + "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." } ], "levels": { @@ -520,15 +530,6 @@ "reportPath": "reports/dev-gate/dev-preflight-report.json", "summary": "Deploy manifests, FRP/master-edge contracts, and safety boundary are source-readable and scoped to hwlab-dev." }, - { - "milestone": "M2", - "issue": "pikasTech/HWLAB#36", - "taskId": "dev-edge-health", - "status": "not_run", - "category": "edge-frp-contract", - "reportPath": "reports/dev-gate/dev-edge-health.json", - "summary": "Committed edge report is contract-only/not-run; it must not be counted as DEV-LIVE." - }, { "milestone": "M3", "issue": "pikasTech/HWLAB#38", @@ -551,10 +552,10 @@ "milestone": "M3", "issue": "pikasTech/HWLAB#39", "taskId": "dev-mvp-gate-report", - "status": "pass", + "status": "blocked", "category": "hardware-loop-local", "reportPath": "reports/dev-gate/dev-mvp-gate-report.json", - "summary": "The local hardware trusted loop smoke passes." + "summary": "Local M3 remains green, but active DEV-LIVE M3 is blocked by hardware loop topology." }, { "milestone": "M4", @@ -571,16 +572,16 @@ "milestone": "M2", "issue": "pikasTech/HWLAB#33", "taskId": "dev-deploy-apply", - "status": "blocked", + "status": "pass", "category": "deploy-apply", "reportPath": "reports/dev-gate/dev-deploy-report.json", - "summary": "DEV apply is blocked before mutation." + "summary": "DEV dry-run preflight passed." }, { "milestone": "M2", "issue": "pikasTech/HWLAB#35", "taskId": "dev-artifact-publish", - "status": "blocked", + "status": "published", "category": "artifact-publish", "reportPath": "reports/dev-gate/dev-artifacts.json", "summary": "Artifact publish preflight exists but is blocked before any real image publish." @@ -604,7 +605,17 @@ "summary": "The M5 orchestration dry-run is green, but it remains fixture-only and does not establish a live DEV gate." } ], - "DEV-LIVE": [], + "DEV-LIVE": [ + { + "milestone": "M2", + "issue": "pikasTech/HWLAB#36", + "taskId": "dev-edge-health", + "status": "blocker", + "category": "edge-frp-contract", + "reportPath": "reports/dev-gate/dev-edge-health.json", + "summary": "Committed edge report proves read-only public HTTP on :16667 /health and /health/live; remaining edge report blocker is DB readiness, not route/frp reachability." + } + ], "BLOCKED": [ { "milestone": "M2", @@ -622,7 +633,7 @@ "status": "not_run", "category": "hardware-loop-live", "reportPath": "reports/dev-gate/dev-m3-hardware-loop.json", - "summary": "No live do.write -> di.read operation was attempted because DEV ingress is blocked." + "summary": "No live DEV operation has run yet." }, { "milestone": "M4", @@ -631,7 +642,7 @@ "status": "blocked", "category": "agent-loop-live-preflight", "reportPath": "reports/dev-gate/dev-m4-agent-loop.json", - "summary": "Blocked before agent scheduling because http://74.48.78.17:16667 is unreachable from this runner." + "summary": "Blocked at DB live readiness before scheduling a DEV agent task." }, { "milestone": "M5", @@ -640,37 +651,7 @@ "status": "blocked", "category": "mvp-e2e-live", "reportPath": "reports/dev-gate/dev-mvp-gate-report.json", - "summary": "The frozen DEV endpoint is not reachable from this runner, so no live DEV gate can be claimed yet." - }, - { - "priority": "P0", - "order": 1, - "type": "environment_blocker", - "scope": "base-image", - "sourceIssue": "pikasTech/HWLAB#35", - "source": "reports/dev-gate/dev-artifacts.json", - "summary": "HWLAB_DEV_BASE_IMAGE is not set and no approved local DEV builder base image was found in the Docker image cache; expected node:20-bookworm-slim or 127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim.", - "nextTask": "Preload node:20-bookworm-slim into the D601 Docker cache, or tag it as 127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim. Set HWLAB_DEV_BASE_IMAGE=node:20-bookworm-slim or HWLAB_DEV_BASE_IMAGE=127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim when invoking artifact publish. Rerun this preflight and require status=ready before #35 artifact publish. Do not use UniDesk runtime, Code Queue runner, backend-core, provider-gateway, or microservice-proxy images as substitutes." - }, - { - "priority": "P1", - "order": 3, - "type": "observability_blocker", - "scope": "artifact-publish", - "sourceIssue": "pikasTech/HWLAB#33", - "source": "reports/dev-gate/dev-deploy-report.json", - "summary": "DEV artifact catalog has no CI publish, registry verification, or registry digests", - "nextTask": "Publish DEV images from the intended commit and update the catalog with registry digests and verification evidence." - }, - { - "priority": "P1", - "order": 3, - "type": "observability_blocker", - "scope": "artifact-source-commit", - "sourceIssue": "pikasTech/HWLAB#33", - "source": "reports/dev-gate/dev-deploy-report.json", - "summary": "deploy/catalog artifact commit 24eb3bf/24eb3bf does not match source 9b47ebe49f70", - "nextTask": "Regenerate deploy/deploy.json and deploy/artifact-catalog.dev.json for the source commit that will be promoted." + "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." }, { "priority": "P1", @@ -732,16 +713,6 @@ "summary": "No SSH maintenance bridge was detected from ssh binary plus known environment variables or ~/.ssh/config metadata.", "nextTask": "Provide a documented read-only maintenance bridge variable or config path if kubectl cannot be mounted directly in the runner." }, - { - "priority": "P1", - "order": 4, - "type": "environment_blocker", - "scope": "kubectl", - "sourceIssue": "pikasTech/HWLAB#33", - "source": "reports/dev-gate/dev-deploy-report.json", - "summary": "kubectl is not installed in the runner", - "nextTask": "Provide a kubectl client configured for the D601 DEV k3s context without exposing token or secret values." - }, { "priority": "P1", "order": 4, @@ -757,10 +728,9 @@ "order": 5, "type": "runtime_blocker", "scope": "cloud-api-db", - "sourceIssue": "pikasTech/HWLAB#33", - "source": "reports/dev-gate/dev-deploy-report.json", - "summary": "cloud-api health reports DB config blocked; missing HWLAB_CLOUD_DB_URL, HWLAB_CLOUD_DB_SSL_MODE", - "nextTask": "Configure and verify the DEV cloud-api DB env readiness through health output, without reading secret values." + "sourceIssue": "pikasTech/HWLAB#36", + "source": "reports/dev-gate/dev-edge-health.json", + "summary": "cloud-api DB env is injected, but runtime health has not attempted a live DB connection" }, { "priority": "P1", @@ -773,108 +743,44 @@ "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": "P2", - "order": 6, - "type": "network_blocker", - "scope": "dev-edge", - "sourceIssue": "pikasTech/HWLAB#34", - "source": "reports/dev-gate/dev-preflight-report.json", - "summary": "http://74.48.78.17:16667/health/live is not reachable from this runner.", - "nextTask": "Bring up or repair the D601-to-master frp route and hwlab-edge-proxy, then rerun the health probe." - }, - { - "priority": "P2", - "order": 6, - "type": "network_blocker", - "scope": "dev-edge-health", - "sourceIssue": "pikasTech/HWLAB#34", - "source": "reports/dev-gate/dev-preflight-report.json", - "summary": "live network probes require --live", - "nextTask": "Repair the master frps/public DEV edge route and rerun the read-only DEV edge health smoke before real deployment." - }, - { - "priority": "P2", - "order": 6, - "type": "network_blocker", - "scope": "dev-ingress-health", + "priority": "P3", + "order": 99, + "type": "runtime_blocker", + "scope": "m3-hardware-loop-runtime", "sourceIssue": "pikasTech/HWLAB#38", "source": "reports/dev-gate/dev-m3-hardware-loop.json", - "summary": "Blocked at the #33 DEV runtime readiness condition: public DEV ingress does not accept HWLAB health requests, so #36/M3 hardware-loop checks were not reached." + "summary": "patch-panel active DO1 -> DI1 connection missing" }, { - "priority": "P2", - "order": 6, - "type": "network_blocker", - "scope": "devPreconditions", + "priority": "P3", + "order": 99, + "type": "runtime_blocker", + "scope": "db-live", "sourceIssue": "pikasTech/HWLAB#37", "source": "reports/dev-gate/dev-m4-agent-loop.json", - "summary": "connect ECONNREFUSED 74.48.78.17:16667" + "summary": "cloud-api /health/live reports DB degraded; connected=false; ready=false." }, { - "priority": "P2", - "order": 6, - "type": "network_blocker", - "scope": "devPreconditions", + "priority": "P3", + "order": 99, + "type": "runtime_blocker", + "scope": "db-live", "sourceIssue": "pikasTech/HWLAB#39", "source": "reports/dev-gate/dev-mvp-gate-report.json", - "summary": "http://74.48.78.17:16667/health and /live both fail with curl exit 7; live DEV ingress evidence is missing." + "summary": "cloud-api /health/live reports DB degraded; db.ready=false, db.connected=false, and live DB evidence is not established." + }, + { + "priority": "P3", + "order": 99, + "type": "runtime_blocker", + "scope": "m3-hardware-loop-runtime", + "sourceIssue": "pikasTech/HWLAB#39", + "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." } ] }, "blockers": [ - { - "id": "dev-artifact-publish:base-image", - "priority": "P0", - "type": "environment_blocker", - "scope": "base-image", - "status": "open", - "source": "reports/dev-gate/dev-artifacts.json", - "sourceIssue": "pikasTech/HWLAB#35", - "summary": "HWLAB_DEV_BASE_IMAGE is not set and no approved local DEV builder base image was found in the Docker image cache; expected node:20-bookworm-slim or 127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim.", - "nextTask": "Preload node:20-bookworm-slim into the D601 Docker cache, or tag it as 127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim. Set HWLAB_DEV_BASE_IMAGE=node:20-bookworm-slim or HWLAB_DEV_BASE_IMAGE=127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim when invoking artifact publish. Rerun this preflight and require status=ready before #35 artifact publish. Do not use UniDesk runtime, Code Queue runner, backend-core, provider-gateway, or microservice-proxy images as substitutes.", - "unblockOrder": 1, - "unblocks": [ - "pikasTech/HWLAB#35", - "pikasTech/HWLAB#33" - ], - "rationale": "Artifact publishing cannot start until an approved Node 20 DEV builder base image is available." - }, - { - "id": "dev-deploy-apply:artifact-publish", - "priority": "P1", - "type": "observability_blocker", - "scope": "artifact-publish", - "status": "open", - "source": "reports/dev-gate/dev-deploy-report.json", - "sourceIssue": "pikasTech/HWLAB#33", - "summary": "DEV artifact catalog has no CI publish, registry verification, or registry digests", - "nextTask": "Publish DEV images from the intended commit and update the catalog with registry digests and verification evidence.", - "unblockOrder": 3, - "unblocks": [ - "pikasTech/HWLAB#35", - "pikasTech/HWLAB#33", - "pikasTech/HWLAB#39" - ], - "rationale": "The gate cannot promote deploy or runtime observations without immutable image provenance and digests." - }, - { - "id": "dev-deploy-apply:artifact-source-commit", - "priority": "P1", - "type": "observability_blocker", - "scope": "artifact-source-commit", - "status": "open", - "source": "reports/dev-gate/dev-deploy-report.json", - "sourceIssue": "pikasTech/HWLAB#33", - "summary": "deploy/catalog artifact commit 24eb3bf/24eb3bf does not match source 9b47ebe49f70", - "nextTask": "Regenerate deploy/deploy.json and deploy/artifact-catalog.dev.json for the source commit that will be promoted.", - "unblockOrder": 3, - "unblocks": [ - "pikasTech/HWLAB#35", - "pikasTech/HWLAB#33", - "pikasTech/HWLAB#39" - ], - "rationale": "The gate cannot promote deploy or runtime observations without immutable image provenance and digests." - }, { "id": "dev-gate-preflight:artifact-catalog", "priority": "P1", @@ -986,25 +892,6 @@ ], "rationale": "D601 hwlab-dev cluster state must be observable read-only before any live apply or M3/M4/M5 acceptance." }, - { - "id": "dev-deploy-apply:kubectl", - "priority": "P1", - "type": "environment_blocker", - "scope": "kubectl", - "status": "open", - "source": "reports/dev-gate/dev-deploy-report.json", - "sourceIssue": "pikasTech/HWLAB#33", - "summary": "kubectl is not installed in the runner", - "nextTask": "Provide a kubectl client configured for the D601 DEV k3s context without exposing token or secret values.", - "unblockOrder": 4, - "unblocks": [ - "pikasTech/HWLAB#34", - "pikasTech/HWLAB#33", - "pikasTech/HWLAB#36", - "pikasTech/HWLAB#38" - ], - "rationale": "D601 hwlab-dev cluster state must be observable read-only before any live apply or M3/M4/M5 acceptance." - }, { "id": "dev-gate-preflight:d601-k3s", "priority": "P1", @@ -1025,15 +912,14 @@ "rationale": "D601 hwlab-dev cluster state must be observable read-only before any live apply or M3/M4/M5 acceptance." }, { - "id": "dev-deploy-apply:cloud-api-db", + "id": "dev-edge-health:cloud-api-db", "priority": "P1", "type": "runtime_blocker", "scope": "cloud-api-db", "status": "open", - "source": "reports/dev-gate/dev-deploy-report.json", - "sourceIssue": "pikasTech/HWLAB#33", - "summary": "cloud-api health reports DB config blocked; missing HWLAB_CLOUD_DB_URL, HWLAB_CLOUD_DB_SSL_MODE", - "nextTask": "Configure and verify the DEV cloud-api DB env readiness through health output, without reading secret values.", + "source": "reports/dev-gate/dev-edge-health.json", + "sourceIssue": "pikasTech/HWLAB#36", + "summary": "cloud-api DB env is injected, but runtime health has not attempted a live DB connection", "unblockOrder": 5, "unblocks": [ "pikasTech/HWLAB#34", @@ -1061,121 +947,72 @@ "rationale": "Cloud API DB env and health readiness block runtime health and MVP evidence even if ingress starts responding." }, { - "id": "dev-gate-preflight:dev-edge", - "priority": "P2", - "type": "network_blocker", - "scope": "dev-edge", - "status": "open", - "source": "reports/dev-gate/dev-preflight-report.json", - "sourceIssue": "pikasTech/HWLAB#34", - "summary": "http://74.48.78.17:16667/health/live is not reachable from this runner.", - "nextTask": "Bring up or repair the D601-to-master frp route and hwlab-edge-proxy, then rerun the health probe.", - "unblockOrder": 6, - "unblocks": [ - "pikasTech/HWLAB#36", - "pikasTech/HWLAB#38", - "pikasTech/HWLAB#37", - "pikasTech/HWLAB#39" - ], - "rationale": "The :6667/frp path must be reachable before any DEV-LIVE M3, M4, or M5 evidence can be collected." - }, - { - "id": "dev-gate-preflight:dev-edge-health", - "priority": "P2", - "type": "network_blocker", - "scope": "dev-edge-health", - "status": "open", - "source": "reports/dev-gate/dev-preflight-report.json", - "sourceIssue": "pikasTech/HWLAB#34", - "summary": "live network probes require --live", - "nextTask": "Repair the master frps/public DEV edge route and rerun the read-only DEV edge health smoke before real deployment.", - "unblockOrder": 6, - "unblocks": [ - "pikasTech/HWLAB#36", - "pikasTech/HWLAB#38", - "pikasTech/HWLAB#37", - "pikasTech/HWLAB#39" - ], - "rationale": "The :6667/frp path must be reachable before any DEV-LIVE M3, M4, or M5 evidence can be collected." - }, - { - "id": "dev-m3-hardware-loop:dev-ingress-health", - "priority": "P2", - "type": "network_blocker", - "scope": "dev-ingress-health", + "id": "dev-m3-hardware-loop:m3-hardware-loop-runtime", + "priority": "P3", + "type": "runtime_blocker", + "scope": "m3-hardware-loop-runtime", "status": "open", "source": "reports/dev-gate/dev-m3-hardware-loop.json", "sourceIssue": "pikasTech/HWLAB#38", - "summary": "Blocked at the #33 DEV runtime readiness condition: public DEV ingress does not accept HWLAB health requests, so #36/M3 hardware-loop checks were not reached.", - "unblockOrder": 6, + "summary": "patch-panel active DO1 -> DI1 connection missing", + "unblockOrder": 99, "unblocks": [ - "pikasTech/HWLAB#36", - "pikasTech/HWLAB#38", - "pikasTech/HWLAB#37", "pikasTech/HWLAB#39" ], - "rationale": "The :6667/frp path must be reachable before any DEV-LIVE M3, M4, or M5 evidence can be collected." + "rationale": "Residual blocker that must be classified before claiming a green DEV gate." }, { - "id": "dev-m4-agent-loop:devPreconditions", - "priority": "P2", - "type": "network_blocker", - "scope": "devPreconditions", + "id": "dev-m4-agent-loop:db-live", + "priority": "P3", + "type": "runtime_blocker", + "scope": "db-live", "status": "open", "source": "reports/dev-gate/dev-m4-agent-loop.json", "sourceIssue": "pikasTech/HWLAB#37", - "summary": "connect ECONNREFUSED 74.48.78.17:16667", - "unblockOrder": 6, + "summary": "cloud-api /health/live reports DB degraded; connected=false; ready=false.", + "unblockOrder": 99, "unblocks": [ - "pikasTech/HWLAB#36", - "pikasTech/HWLAB#38", - "pikasTech/HWLAB#37", "pikasTech/HWLAB#39" ], - "rationale": "The :6667/frp path must be reachable before any DEV-LIVE M3, M4, or M5 evidence can be collected." + "rationale": "Residual blocker that must be classified before claiming a green DEV gate." }, { - "id": "dev-mvp-gate-report:devPreconditions", - "priority": "P2", - "type": "network_blocker", - "scope": "devPreconditions", + "id": "dev-mvp-gate-report:db-live", + "priority": "P3", + "type": "runtime_blocker", + "scope": "db-live", "status": "open", "source": "reports/dev-gate/dev-mvp-gate-report.json", "sourceIssue": "pikasTech/HWLAB#39", - "summary": "http://74.48.78.17:16667/health and /live both fail with curl exit 7; live DEV ingress evidence is missing.", - "unblockOrder": 6, + "summary": "cloud-api /health/live reports DB degraded; db.ready=false, db.connected=false, and live DB evidence is not established.", + "unblockOrder": 99, "unblocks": [ - "pikasTech/HWLAB#36", - "pikasTech/HWLAB#38", - "pikasTech/HWLAB#37", "pikasTech/HWLAB#39" ], - "rationale": "The :6667/frp path must be reachable before any DEV-LIVE M3, M4, or M5 evidence can be collected." + "rationale": "Residual blocker that must be classified before claiming a green DEV gate." + }, + { + "id": "dev-mvp-gate-report:m3-hardware-loop-runtime", + "priority": "P3", + "type": "runtime_blocker", + "scope": "m3-hardware-loop-runtime", + "status": "open", + "source": "reports/dev-gate/dev-mvp-gate-report.json", + "sourceIssue": "pikasTech/HWLAB#39", + "summary": "Live M3 smoke reached DEV simulators, but patch-panel active DO1 -> DI1 connection is missing.", + "unblockOrder": 99, + "unblocks": [ + "pikasTech/HWLAB#39" + ], + "rationale": "Residual blocker that must be classified before claiming a green DEV gate." } ], "nextSteps": [ { "order": 1, - "blockerOrder": 1, - "priority": "P0", - "scopes": [ - "base-image" - ], - "sourceIssues": [ - "pikasTech/HWLAB#33", - "pikasTech/HWLAB#35" - ], - "rationale": "Artifact publishing cannot start until an approved Node 20 DEV builder base image is available.", - "action": "Preload node:20-bookworm-slim into the D601 Docker cache, or tag it as 127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim. Set HWLAB_DEV_BASE_IMAGE=node:20-bookworm-slim or HWLAB_DEV_BASE_IMAGE=127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim when invoking artifact publish. Rerun this preflight and require status=ready before #35 artifact publish. Do not use UniDesk runtime, Code Queue runner, backend-core, provider-gateway, or microservice-proxy images as substitutes.", - "evidenceRequired": "Base-image preflight status=ready with approved Node 20 builder base and no UniDesk/runtime substitute." - }, - { - "order": 2, "blockerOrder": 3, "priority": "P1", "scopes": [ - "artifact-publish", - "artifact-source-commit", "artifact-catalog", "dev-artifact-publish", "ghcr" @@ -1187,18 +1024,17 @@ "pikasTech/HWLAB#39" ], "rationale": "The gate cannot promote deploy or runtime observations without immutable image provenance and digests.", - "action": "Publish DEV images from the intended commit and update the catalog with registry digests and verification evidence.", + "action": "Run the DEV artifact publish workflow, then record only real sha256 digests with `node scripts/refresh-artifact-catalog.mjs --target-ref origin/main --publish-report reports/dev-gate/dev-artifacts.json`; if publish is still blocked, keep not_published via `node scripts/refresh-artifact-catalog.mjs --target-ref origin/main --blocked`.", "evidenceRequired": "Artifact publish report with ciPublished=true, registryVerified=true, and sha256 digest for each frozen service ID." }, { - "order": 3, + "order": 2, "blockerOrder": 4, "priority": "P1", "scopes": [ "d601-k3s-client-binary", "d601-kubeconfig-path", "d601-maintenance-ssh-bridge", - "kubectl", "d601-k3s" ], "sourceIssues": [ @@ -1213,7 +1049,7 @@ "evidenceRequired": "Read-only kubectl/k3s report proving pods/services/configmaps are observable in hwlab-dev without reading Secrets." }, { - "order": 4, + "order": 3, "blockerOrder": 5, "priority": "P1", "scopes": [ @@ -1223,32 +1059,29 @@ "sourceIssues": [ "pikasTech/HWLAB#33", "pikasTech/HWLAB#34", + "pikasTech/HWLAB#36", "pikasTech/HWLAB#39" ], "rationale": "Cloud API DB env and health readiness block runtime health and MVP evidence even if ingress starts responding.", - "action": "Configure and verify the DEV cloud-api DB env readiness through health output, without reading secret values.", + "action": "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.", "evidenceRequired": "Cloud API health/live output showing DB env ready and redacted secret references, without secret material." }, { - "order": 5, - "blockerOrder": 6, - "priority": "P2", + "order": 4, + "blockerOrder": 99, + "priority": "P3", "scopes": [ - "dev-edge", - "dev-edge-health", - "dev-ingress-health", - "devPreconditions" + "m3-hardware-loop-runtime", + "db-live" ], "sourceIssues": [ - "pikasTech/HWLAB#34", - "pikasTech/HWLAB#36", "pikasTech/HWLAB#37", "pikasTech/HWLAB#38", "pikasTech/HWLAB#39" ], - "rationale": "The :6667/frp path must be reachable before any DEV-LIVE M3, M4, or M5 evidence can be collected.", - "action": "Bring up or repair the D601-to-master frp route and hwlab-edge-proxy, then rerun the health probe.", - "evidenceRequired": "Read-only DEV route observation for :6667/frp/edge/router with HWLAB service identity and artifact identity." + "rationale": "Residual blocker that must be classified before claiming a green DEV gate.", + "action": "Resolve the blocker and attach source/local/dry-run/DEV-live evidence at the correct level.", + "evidenceRequired": "A committed report with the exact evidence level and command used." } ], "validationCommands": [ diff --git a/reports/dev-gate/dev-m5-gate-aggregator-v2.md b/reports/dev-gate/dev-m5-gate-aggregator-v2.md index e06651af..a5b74705 100644 --- a/reports/dev-gate/dev-m5-gate-aggregator-v2.md +++ b/reports/dev-gate/dev-m5-gate-aggregator-v2.md @@ -1,12 +1,12 @@ # HWLAB M5 DEV Gate Aggregator v2 Status: blocked -Generated from: `1e9591a6611e` +Generated from: `d4fe2cf1bb8a` Scope: DEV only, report-only ## Summary -SOURCE, LOCAL, and DRY-RUN evidence exists, but DEV-LIVE acceptance is blocked by artifact, observability, DB, edge/frp, and loop evidence gaps. +SOURCE, LOCAL, DRY-RUN, and edge DEV-LIVE evidence exists, but acceptance is still blocked by artifact, observability, DB, and loop evidence gaps. ## Milestones @@ -14,9 +14,9 @@ SOURCE, LOCAL, and DRY-RUN evidence exists, but DEV-LIVE acceptance is blocked b | --- | --- | --- | --- | --- | | M0 | pass | SOURCE | missing_or_blocked | contract source is available; highest visible level is SOURCE; status is pass. | | M1 | pass | LOCAL | missing_or_blocked | local smoke is available; highest visible level is LOCAL; status is pass. | -| M2 | blocked | DRY-RUN | missing_or_blocked | deploy/runtime readiness is blocked before live DEV; highest visible level is DRY-RUN; status is blocked. | +| M2 | blocked | DEV-LIVE | missing_or_blocked | deploy/runtime readiness is blocked before live DEV; highest visible level is DEV-LIVE; status is blocked. | | M3 | blocked | LOCAL | missing_or_blocked | hardware loop has source/local shape but no live operation; highest visible level is LOCAL; status is blocked. | -| M4 | blocked | LOCAL | missing_or_blocked | agent loop has local smoke but live preflight is blocked; highest visible level is LOCAL; status is blocked. | +| M4 | not_run | LOCAL | missing_or_blocked | agent loop has local smoke but live preflight is blocked; highest visible level is LOCAL; status is not_run. | | M5 | blocked | DRY-RUN | missing_or_blocked | dry-run is green but live MVP gate is blocked; highest visible level is DRY-RUN; status is blocked. | ## #9 DoD Checks @@ -27,7 +27,7 @@ SOURCE, LOCAL, and DRY-RUN evidence exists, but DEV-LIVE acceptance is blocked b | m1-local-smoke | pass | LOCAL | M1 local smoke is not a live DEV substitute. | | artifact-publish-digests | blocked | BLOCKED | artifactState=contract-skeleton, ciPublished=false, registryVerified=false, sha256=0, not_published=13 | | d601-k3s-observability | blocked | BLOCKED | D601 runner lacks kubectl/k3s/kubeconfig observability for hwlab-dev. | -| dev-edge-frp-6667 | blocked | BLOCKED | No committed report proves live HTTP 200/JSON on http://74.48.78.17:16667. | +| dev-edge-frp-16667 | pass | DEV-LIVE | Committed edge report proves read-only public HTTP on :16667 /health and /health/live; old preflight network probe blockers are stale. | | cloud-api-db-ready | blocked | BLOCKED | Manifest-level DB env exists, but live DB health readiness is still blocked/missing. | | m5-mvp-dev-live | blocked | BLOCKED | M5 dry-run passed; bounded DEV-LIVE MVP e2e has not passed. | @@ -35,37 +35,30 @@ SOURCE, LOCAL, and DRY-RUN evidence exists, but DEV-LIVE acceptance is blocked b | Priority | Order | Type | Scope | Summary | | --- | ---: | --- | --- | --- | -| P0 | 1 | environment_blocker | base-image | HWLAB_DEV_BASE_IMAGE is not set and no approved local DEV builder base image was found in the Docker image cache; expected node:20-bookworm-slim or 127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim. | -| P1 | 3 | observability_blocker | artifact-publish | DEV artifact catalog has no CI publish, registry verification, or registry digests | -| P1 | 3 | observability_blocker | artifact-source-commit | deploy/catalog artifact commit 24eb3bf/24eb3bf does not match source 9b47ebe49f70 | | P1 | 3 | runtime_blocker | artifact-catalog | deploy/artifact-catalog.dev.json does not prove published artifacts for origin/main 1a2efd4; ciPublished=false, registryVerified=false, not_published=13. | | P1 | 3 | runtime_blocker | dev-artifact-publish | reports/dev-gate/dev-artifacts.json does not prove all HWLAB service artifacts for origin/main 1a2efd4; current status is blocked with 0/13 published. | | P1 | 3 | runtime_blocker | ghcr | This preflight could not verify GHCR manifests for the DEV catalog images without reading credentials. | | P1 | 4 | environment_blocker | d601-k3s-client-binary | Neither kubectl nor k3s is installed in this runner PATH. | | P1 | 4 | environment_blocker | d601-kubeconfig-path | No readable KUBECONFIG/default k3s kubeconfig path was found by metadata checks. | | P1 | 4 | environment_blocker | d601-maintenance-ssh-bridge | No SSH maintenance bridge was detected from ssh binary plus known environment variables or ~/.ssh/config metadata. | -| P1 | 4 | environment_blocker | kubectl | kubectl is not installed in the runner | | P1 | 4 | environment_blocker | d601-k3s | D601 runner lacks kubectl and no default kubeconfig was used by this preflight. | -| P1 | 5 | runtime_blocker | cloud-api-db | cloud-api health reports DB config blocked; missing HWLAB_CLOUD_DB_URL, HWLAB_CLOUD_DB_SSL_MODE | +| P1 | 5 | runtime_blocker | cloud-api-db | cloud-api DB env is injected, but runtime health has not attempted a live DB connection | | 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. | -| P2 | 6 | network_blocker | dev-edge | http://74.48.78.17:16667/health/live is not reachable from this runner. | -| P2 | 6 | network_blocker | dev-edge-health | live network probes require --live | -| P2 | 6 | network_blocker | dev-ingress-health | Blocked at the #33 DEV runtime readiness condition: public DEV ingress does not accept HWLAB health requests, so #36/M3 hardware-loop checks were not reached. | -| P2 | 6 | network_blocker | devPreconditions | connect ECONNREFUSED 74.48.78.17:16667 | -| P2 | 6 | network_blocker | devPreconditions | http://74.48.78.17:16667/health and /live both fail with curl exit 7; live DEV ingress evidence is missing. | +| P3 | 99 | runtime_blocker | m3-hardware-loop-runtime | patch-panel active DO1 -> DI1 connection missing | +| P3 | 99 | runtime_blocker | db-live | cloud-api /health/live reports DB degraded; connected=false; ready=false. | +| P3 | 99 | runtime_blocker | db-live | cloud-api /health/live reports DB degraded; db.ready=false, db.connected=false, and live DB evidence is not established. | +| P3 | 99 | runtime_blocker | m3-hardware-loop-runtime | Live M3 smoke reached DEV simulators, but patch-panel active DO1 -> DI1 connection is missing. | ## Next Unblock Order -1. Preload node:20-bookworm-slim into the D601 Docker cache, or tag it as 127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim. Set HWLAB_DEV_BASE_IMAGE=node:20-bookworm-slim or HWLAB_DEV_BASE_IMAGE=127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim when invoking artifact publish. Rerun this preflight and require status=ready before #35 artifact publish. Do not use UniDesk runtime, Code Queue runner, backend-core, provider-gateway, or microservice-proxy images as substitutes. - Evidence required: Base-image preflight status=ready with approved Node 20 builder base and no UniDesk/runtime substitute. -2. Publish DEV images from the intended commit and update the catalog with registry digests and verification evidence. +1. Run the DEV artifact publish workflow, then record only real sha256 digests with `node scripts/refresh-artifact-catalog.mjs --target-ref origin/main --publish-report reports/dev-gate/dev-artifacts.json`; if publish is still blocked, keep not_published via `node scripts/refresh-artifact-catalog.mjs --target-ref origin/main --blocked`. Evidence required: Artifact publish report with ciPublished=true, registryVerified=true, and sha256 digest for each frozen service ID. -3. Install kubectl in the D601 Code Queue runner image, or mount an approved k3s kubectl client path for read-only hwlab-dev observation. +2. Install kubectl in the D601 Code Queue runner image, or mount an approved k3s kubectl client path for read-only hwlab-dev observation. Evidence required: Read-only kubectl/k3s report proving pods/services/configmaps are observable in hwlab-dev without reading Secrets. -4. Configure and verify the DEV cloud-api DB env readiness through health output, without reading secret values. +3. 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. Evidence required: Cloud API health/live output showing DB env ready and redacted secret references, without secret material. -5. Bring up or repair the D601-to-master frp route and hwlab-edge-proxy, then rerun the health probe. - Evidence required: Read-only DEV route observation for :6667/frp/edge/router with HWLAB service identity and artifact identity. +4. Resolve the blocker and attach source/local/dry-run/DEV-live evidence at the correct level. + Evidence required: A committed report with the exact evidence level and command used. ## Validation diff --git a/reports/dev-gate/dev-mvp-gate-report.json b/reports/dev-gate/dev-mvp-gate-report.json index 53c80885..3cb12cea 100644 --- a/reports/dev-gate/dev-mvp-gate-report.json +++ b/reports/dev-gate/dev-mvp-gate-report.json @@ -4,7 +4,7 @@ "reportVersion": "v1", "issue": "pikasTech/HWLAB#39", "taskId": "dev-mvp-gate-report", - "commitId": "6eb4c199b0c63cca7fd68fc3306f7a9cbe4323ea", + "commitId": "86d769525caf1db513b93cb67c2c8ee8863dd4b1", "acceptanceLevel": "dev_mvp_gate", "devOnly": true, "prodDisabled": true, @@ -81,27 +81,46 @@ }, "devPreconditions": { "status": "blocked", + "classification": "DB live; hardware loop", "requirements": [ - "Obtain a live HTTP 200/JSON health observation from http://74.48.78.17:16667/health and /live", - "Record live route observations for hwlab-edge-proxy, hwlab-tunnel-client, hwlab-router, hwlab-cloud-api/web, hwlab-gateway, hwlab-gateway-simu, hwlab-box-simu, hwlab-patch-panel, hwlab-agent-mgr, hwlab-agent-worker, and hwlab-agent-skills", + "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", + "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": [ - "curl -fsS --max-time 5 http://74.48.78.17:16667/health", - "curl -fsS --max-time 5 http://74.48.78.17:16667/live" + "curl -fsS --max-time 8 http://74.48.78.17:16666/", + "curl -fsS --max-time 8 http://74.48.78.17:16667/health/live", + "curl -fsS --max-time 8 http://74.48.78.17:16667/health", + "HWLAB_DEV_BOX_SIMU_1_URL=http://10.42.0.200:7201 HWLAB_DEV_BOX_SIMU_2_URL=http://10.42.0.208:7201 HWLAB_DEV_GATEWAY_SIMU_1_URL=http://10.42.0.209:7101 HWLAB_DEV_GATEWAY_SIMU_2_URL=http://10.42.0.204:7101 HWLAB_DEV_PATCH_PANEL_URL=http://10.42.0.205:7301 node scripts/dev-m3-hardware-loop-smoke.mjs --live --confirm-dev --confirmed-non-production", + "node scripts/dev-m4-agent-loop-smoke.mjs --live --confirm-dev --confirmed-non-production" ], "evidence": [ - "curl exit 7 for /health: could not connect to 74.48.78.17 port 6667", - "curl exit 7 for /live: could not connect to 74.48.78.17 port 6667" + "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", + "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" ], - "summary": "The frozen DEV endpoint is not reachable from this runner, so no live DEV gate can be claimed yet." + "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." }, "blockers": [ { - "type": "network_blocker", - "scope": "devPreconditions", + "type": "runtime_blocker", + "scope": "db-live", "status": "open", - "summary": "http://74.48.78.17:16667/health and /live both fail with curl exit 7; live DEV ingress evidence is missing." + "classification": "DB live", + "summary": "cloud-api /health/live reports DB degraded; db.ready=false, db.connected=false, and live DB evidence is not established." + }, + { + "type": "runtime_blocker", + "scope": "m3-hardware-loop-runtime", + "status": "open", + "classification": "hardware loop", + "summary": "Live M3 smoke reached DEV simulators, but patch-panel active DO1 -> DI1 connection is missing." } ], "milestones": [ @@ -155,43 +174,87 @@ }, { "id": "M3", - "status": "pass", + "status": "blocked", "commands": [ - "node scripts/m3-hardware-loop-smoke.mjs" + "node scripts/m3-hardware-loop-smoke.mjs", + "node scripts/dev-m3-hardware-loop-smoke.mjs --live --confirm-dev --confirmed-non-production" ], "evidence": [ - "M3 hardware loop smoke passed", - "topology: 2 box simulators, 2 gateway simulators, 1 patch panel", - "wiring: box-simu-1 DO1 -> box-simu-2 DI1 via hwlab-patch-panel" + "Local M3 hardware loop smoke passed", + "Live DEV M3 smoke reached 16667 ingress and direct simulator/patch-panel Pod URLs", + "Live DEV M3 blocked: patch-panel active DO1 -> DI1 connection missing" ], - "summary": "The local hardware trusted loop smoke passes." + "summary": "Local M3 remains green, but active DEV-LIVE M3 is blocked by hardware loop topology.", + "blocker": "hardware loop" }, { "id": "M4", - "status": "pass", + "status": "blocked", "commands": [ - "node scripts/m4-agent-loop-smoke.mjs" + "node scripts/m4-agent-loop-smoke.mjs", + "node scripts/dev-m4-agent-loop-smoke.mjs --live --confirm-dev --confirmed-non-production" ], "evidence": [ - "[m4-smoke] ok m4-agent-automation-loop-local-contract-smoke" + "[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" ], - "summary": "The local agent automation loop smoke passes." + "summary": "Local M4 remains green, but active DEV-LIVE M4 is blocked at DB live readiness before agent runtime scheduling.", + "blocker": "DB live" }, { "id": "M5", - "status": "pass", + "status": "blocked", "commands": [ "node tools/hwlab-cli/bin/hwlab-cli.mjs health", "node tools/hwlab-cli/bin/hwlab-cli.mjs test e2e --env dev --mvp --dry-run", "node scripts/m5-mvp-e2e-dry-run.mjs" ], "evidence": [ - "hwlab-cli health -> status: ok, environment: dev, endpoint: http://74.48.78.17:16667, projects: 2", + "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" + "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" ], - "summary": "The M5 orchestration is green in dry-run mode, but it stays fixture-only and does not claim live DEV readiness." + "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" } ], - "notes": "Blocked gate report. Local contract, smoke, and dry-run checks pass on origin/main, but live DEV ingress is unreachable from this runner." + "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.", + "blockedClassification": [ + { + "category": "DB live", + "status": "blocked", + "evidence": "16667/health/live serviceId=hwlab-cloud-api status=degraded db.ready=false db.connected=false" + }, + { + "category": "agent runtime", + "status": "not_run", + "evidence": "M4 stopped before agent scheduling because DB live is blocked" + }, + { + "category": "hardware loop", + "status": "blocked", + "evidence": "M3 stopped on missing patch-panel DO1 -> DI1 active connection" + }, + { + "category": "evidence/audit", + "status": "not_run", + "evidence": "M3/M4 did not reach accepted hardware operations requiring audit/evidence closure" + }, + { + "category": "CD apply", + "status": "not_run", + "evidence": "No deploy/apply command was run in this #64 retest" + }, + { + "category": "frp", + "status": "pass", + "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" + } + ] } diff --git a/reports/dev-gate/dev-mvp-gate-report.md b/reports/dev-gate/dev-mvp-gate-report.md index 255f8336..c4895ec5 100644 --- a/reports/dev-gate/dev-mvp-gate-report.md +++ b/reports/dev-gate/dev-mvp-gate-report.md @@ -2,14 +2,14 @@ Status: blocked -Baseline: `6eb4c199b0c63cca7fd68fc3306f7a9cbe4323ea` +Baseline: `86d769525caf1db513b93cb67c2c8ee8863dd4b1` Scope: DEV only ## Summary -M0-M5 local contract, smoke, and dry-run checks pass on the frozen `origin/main` baseline. The live DEV gate is still blocked because `http://74.48.78.17:16667` is not reachable from this runner. +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. -## Evidence +## Commands - `node scripts/validate-contract.mjs` - `node scripts/validate-m0-contract.mjs` @@ -24,23 +24,38 @@ M0-M5 local contract, smoke, and dry-run checks pass on the frozen `origin/main` - `node tools/hwlab-cli/bin/hwlab-cli.mjs health` - `node tools/hwlab-cli/bin/hwlab-cli.mjs test e2e --env dev --mvp --dry-run` - `node scripts/m5-mvp-e2e-dry-run.mjs` -- `curl -fsS --max-time 5 http://74.48.78.17:16667/health` -- `curl -fsS --max-time 5 http://74.48.78.17:16667/live` +- `curl -fsS --max-time 8 http://74.48.78.17:16666/` +- `curl -fsS --max-time 8 http://74.48.78.17:16667/health/live` +- `curl -fsS --max-time 8 http://74.48.78.17:16667/health` +- `HWLAB_DEV_BOX_SIMU_1_URL=http://10.42.0.200:7201 HWLAB_DEV_BOX_SIMU_2_URL=http://10.42.0.208:7201 HWLAB_DEV_GATEWAY_SIMU_1_URL=http://10.42.0.209:7101 HWLAB_DEV_GATEWAY_SIMU_2_URL=http://10.42.0.204:7101 HWLAB_DEV_PATCH_PANEL_URL=http://10.42.0.205:7301 node scripts/dev-m3-hardware-loop-smoke.mjs --live --confirm-dev --confirmed-non-production` +- `node scripts/dev-m4-agent-loop-smoke.mjs --live --confirm-dev --confirmed-non-production` -## Result +## Milestones -- `M0`: pass -- `M1`: pass -- `M2`: pass -- `M3`: pass -- `M4`: pass -- `M5`: pass -- `overall`: blocked +- `M0`: pass - Frozen contract, artifact, boundary, drift, and evidence fixtures are parseable and aligned to the DEV boundary. +- `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. -## Minimal Next Step +## Blocked Classification -Obtain live `200`/JSON health observations from `http://74.48.78.17:16667/health` and `/live`, then capture the live route observations for the DEV ingress chain without switching to PROD or heavy e2e. +| 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 | +| 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 | -## Blocker +## Blockers -The frozen DEV endpoint returns connection failures from this runner, so no live DEV ingress evidence can be claimed yet. +- DB live: cloud-api /health/live reports DB degraded; db.ready=false, db.connected=false, and live DB evidence is not established. +- 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. diff --git a/scripts/dev-m3-hardware-loop-smoke.mjs b/scripts/dev-m3-hardware-loop-smoke.mjs index 645c20aa..97efaf23 100644 --- a/scripts/dev-m3-hardware-loop-smoke.mjs +++ b/scripts/dev-m3-hardware-loop-smoke.mjs @@ -704,12 +704,14 @@ async function main() { }; report.blockers.push({ type: "network_blocker", - scope: "dev-ingress-health", + scope: "frp", status: "open", + classification: "frp", summary: "Blocked at the #33 DEV runtime readiness condition: public DEV ingress does not accept HWLAB health requests, so #36/M3 hardware-loop checks were not reached." }); report.summary = { status: "blocked", + classification: "frp", observedAt, result: "No live DEV M3 evidence was produced; fixture-backed local evidence was not used as a substitute." }; @@ -726,10 +728,12 @@ async function main() { type: "runtime_blocker", scope: "m3-service-discovery", status: "open", + classification: "hardware loop", summary: `DEV ingress is reachable, but M3 smoke lacks direct DEV service URLs: ${missing.join(", ")}.` }); report.summary = { status: "blocked", + classification: "hardware loop", observedAt, result: "DEV ingress was reachable, but live M3 simulator and patch-panel targets were not discoverable." }; @@ -804,10 +808,12 @@ async function main() { type: "runtime_blocker", scope: "m3-hardware-loop-runtime", status: "open", + classification: "hardware loop", summary: error instanceof Error ? error.message : String(error) }); report.summary = { status: "blocked", + classification: "hardware loop", observedAt, result: "Live DEV M3 runtime was reachable but did not satisfy the M3 hardware-loop contract." }; diff --git a/scripts/dev-m4-agent-loop-smoke.mjs b/scripts/dev-m4-agent-loop-smoke.mjs index 27160914..7f91a620 100644 --- a/scripts/dev-m4-agent-loop-smoke.mjs +++ b/scripts/dev-m4-agent-loop-smoke.mjs @@ -7,9 +7,10 @@ import { readFile, writeFile, mkdir } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; +import { DEV_ENDPOINT, ENVIRONMENT_DEV } from "../internal/protocol/index.mjs"; + const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const fixedNow = () => "2026-05-21T00:00:00.000Z"; -const DEV_ENDPOINT = "http://74.48.78.17:16667"; const requiredDocs = ["docs/dev-acceptance-matrix.md", "docs/dev-m4-agent-loop.md"]; const reportPath = "reports/dev-gate/dev-m4-agent-loop.json"; const preflightCommand = "node scripts/dev-m4-agent-loop-smoke.mjs --live --confirm-dev --confirmed-non-production"; @@ -116,9 +117,10 @@ function blockerForResult(result) { ? [ { type: result.blockerType, - scope: "devPreconditions", + scope: result.blockerScope ?? "devPreconditions", status: "open", - summary: result.blockerSummary + summary: result.blockerSummary, + classification: result.blockedClassification ?? "other" } ] : []; @@ -170,8 +172,9 @@ function buildReport(fixture, evidence, result) { }, devPreconditions: { status: statusForResult(result), + classification: result.blockedClassification ?? "none", requirements: [ - "DEV route remains frozen at http://74.48.78.17:16667", + `DEV route remains frozen at ${DEV_ENDPOINT}`, "No secret reads, real deployment, or long-running agent task is attempted", "Agent manager, worker, and skills are reachable only through the cloud API boundary" ], @@ -180,6 +183,7 @@ function buildReport(fixture, evidence, result) { blockers: blockerForResult(result), livePreflight: { status: result.blocked ? "blocked" : "pass", + classification: result.blockedClassification ?? "none", commands: [preflightCommand], evidence: evidence.length ? evidence : ["No live DEV observation was recorded."], summary: result.summary @@ -204,6 +208,8 @@ async function main() { let result = { blocked: true, blockerType: "network_blocker", + blockerScope: "frp", + blockedClassification: "frp", blockerSummary: "The fixed DEV endpoint did not accept a live connection from this runner.", summary: `Blocked before agent scheduling because ${DEV_ENDPOINT} is not reachable from this D601 runner.` }; @@ -214,6 +220,8 @@ async function main() { result = { blocked: true, blockerType: "network_blocker", + blockerScope: "frp", + blockedClassification: "frp", blockerSummary: `DEV health returned HTTP ${health.statusCode}.`, summary: `Blocked on DEV ingress health because ${DEV_ENDPOINT}/health did not return success.` }; @@ -221,15 +229,27 @@ async function main() { const body = health.body || {}; evidence.push(`health:${body.serviceId}:${body.environment}:${body.status}`); - const live = await requestJson(`${DEV_ENDPOINT}/live`); + const live = await requestJson(`${DEV_ENDPOINT}/health/live`); const liveBody = live.body || {}; if (live.statusCode < 200 || live.statusCode >= 300 || liveBody?.serviceId !== "hwlab-cloud-api") { result = { blocked: true, - blockerType: "runtime_blocker", + blockerType: "network_blocker", + blockerScope: "frp", + blockedClassification: "frp", 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)) { + evidence.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 { evidence.push(`live:${liveBody.serviceId}:${liveBody.status}`); @@ -246,51 +266,75 @@ async function main() { meta: { traceId: "trc_dev_m4_health", serviceId: "hwlab-cli", - environment: "dev" + environment: ENVIRONMENT_DEV } }) }); const rpcHealthBody = rpcHealth.body || {}; evidence.push(`rpc-health:${rpcHealthBody.result?.serviceId ?? "unknown"}`); - - 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 - }, - meta: { - traceId: "trc_dev_m4_hw", - serviceId: "hwlab-cli", - environment: "dev" - } - }) - }); - const rpcHardwareBody = rpcHardware.body || {}; - const accepted = rpcHardwareBody.result?.accepted === true; - const status = rpcHardwareBody.result?.status || rpcHardwareBody.error?.message || "unknown"; - evidence.push(`rpc-hardware:${status}`); - - if (!accepted) { + if (rpcHealth.statusCode < 200 || rpcHealth.statusCode >= 300 || rpcHealthBody.error) { result = { blocked: true, blockerType: "agent_blocker", - blockerSummary: "hardware.operation.request remains a skeleton response in the current DEV runtime.", - summary: "Blocked by M3 readiness because the agent hardware dispatch path is still skeleton-only." + 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, - 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 + }, + 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"; + evidence.push(`rpc-hardware:${status}`); + + if (!accepted) { + result = { + blocked: true, + blockerType: "agent_blocker", + blockerScope: "hardware-loop", + blockedClassification: "hardware loop", + blockerSummary: "hardware.operation.request remains a skeleton response in the current DEV runtime.", + summary: "Blocked by M3 readiness because the agent hardware dispatch path is still skeleton-only." + }; + } 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." + }; + } } } } @@ -298,6 +342,8 @@ async function main() { result = { blocked: true, blockerType: "network_blocker", + blockerScope: "frp", + blockedClassification: "frp", blockerSummary: error instanceof Error ? error.message : String(error), summary: `Blocked before agent scheduling because ${DEV_ENDPOINT} is unreachable from this runner.` }; @@ -310,6 +356,7 @@ async function main() { reportPath, status: report.devPreconditions.status, blocker: report.blockers[0] ?? null, + classification: report.devPreconditions.classification, evidence: report.livePreflight.evidence, summary: report.livePreflight.summary, observedAt: fixedNow() @@ -317,4 +364,20 @@ async function main() { process.stdout.write("\n"); } +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(); diff --git a/scripts/l6-cli-web-smoke.mjs b/scripts/l6-cli-web-smoke.mjs index 4f529967..2cda0dc4 100644 --- a/scripts/l6-cli-web-smoke.mjs +++ b/scripts/l6-cli-web-smoke.mjs @@ -66,7 +66,9 @@ const liveBlocked = await captureCli([ assert.equal(liveBlocked.exitCode, 2); const liveBlockedJson = JSON.parse(liveBlocked.stderr); assert.equal(liveBlockedJson.code, "BLOCKED"); -assert.equal(liveBlockedJson.blockers[0].type, "network_blocker"); +assert.equal(liveBlockedJson.blockers[0].type, "runtime_blocker"); +assert.equal(liveBlockedJson.blockers[0].scope, "db-live"); +assert.ok(liveBlockedJson.blockers.some((blocker) => blocker.scope === "m3-hardware-loop-runtime")); assert.equal(gateSummary.endpoint, summary.endpoint); assert.equal(gateSummary.gateStatus, "blocked"); diff --git a/scripts/m5-mvp-e2e-dry-run.mjs b/scripts/m5-mvp-e2e-dry-run.mjs index 51d5405f..dbd384fd 100644 --- a/scripts/m5-mvp-e2e-dry-run.mjs +++ b/scripts/m5-mvp-e2e-dry-run.mjs @@ -5,6 +5,8 @@ import { readFile, stat } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; +import { DEV_ENDPOINT, ENVIRONMENT_DEV } from "../internal/protocol/index.mjs"; + const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const planPath = "fixtures/mvp/m5-e2e/dry-run-plan.json"; const checklistPath = "docs/dev-acceptance-checklist.json"; @@ -12,8 +14,6 @@ const matrixPath = "docs/dev-acceptance-matrix.md"; const runtimePath = "fixtures/mvp/runtime.json"; const contractPath = "protocol/mvp-e2e-contract.md"; const commonSchemaPath = "protocol/schemas/common.json"; -const DEV_ENDPOINT = "http://74.48.78.17:16667"; -const ENVIRONMENT_DEV = "dev"; const JSON_RPC_VERSION = "2.0"; let serviceIds = []; let serviceIdSet = new Set(); diff --git a/scripts/src/dev-evidence-blocker-aggregator.mjs b/scripts/src/dev-evidence-blocker-aggregator.mjs index f9e4fd66..456a43a7 100644 --- a/scripts/src/dev-evidence-blocker-aggregator.mjs +++ b/scripts/src/dev-evidence-blocker-aggregator.mjs @@ -239,7 +239,7 @@ function applyPriority(blocker) { }; } - if (blocker.scope.includes("edge") || blocker.scope.includes("ingress") || blocker.summary.includes("6667")) { + if (isEdgeOrFrpBlocker(blocker)) { return { ...blocker, priority: "P2", @@ -258,6 +258,16 @@ function applyPriority(blocker) { }; } +function isEdgeOrFrpBlocker(blocker) { + return blocker.scope.includes("edge") || + blocker.scope.includes("ingress") || + blocker.scope.includes("frp") || + blocker.summary.includes(":16667") || + blocker.summary.includes("16667") || + blocker.summary.includes(":6667") || + blocker.summary.includes("6667"); +} + function sourceEntry(entry) { return { milestone: entry.milestone, @@ -294,6 +304,7 @@ function collectM2Evidence(reports) { const edge = reports.devEdgeHealth; const d601 = reports.d601Observability; const artifactIdentity = preflight.artifactIdentity; + const edgeLive = hasCurrentLiveEdgeEvidence(edge); return [ reportEvidence({ @@ -336,7 +347,7 @@ function collectM2Evidence(reports) { }), reportEvidence({ milestone: "M2", - level: "SOURCE", + level: edgeLive ? "DEV-LIVE" : "SOURCE", report: edge, status: edge.edgeHealth?.status ?? primaryStatus(edge), category: "edge-frp-contract", @@ -346,7 +357,9 @@ function collectM2Evidence(reports) { `cloudApiDb=${edge.edgeHealth?.contracts?.deploy?.cloudApiDb?.status ?? "unknown"}` ], commands: edge.validationCommands, - summary: "Committed edge report is contract-only/not-run; it must not be counted as DEV-LIVE." + summary: edgeLive + ? "Committed edge report proves read-only public HTTP on :16667 /health and /health/live; remaining edge report blocker is DB readiness, not route/frp reachability." + : "Committed edge report is contract-only/not-run; it must not be counted as DEV-LIVE." }), reportEvidence({ milestone: "M2", @@ -473,12 +486,21 @@ function collectBlockers(reports) { const blockers = []; for (const report of Object.values(reports)) { for (const blocker of report.blockers ?? []) { + if (isStaleLegacyIngressBlocker(blocker, report, reports)) { + continue; + } blockers.push(normalizeBlocker(blocker, report)); } for (const blocker of report.artifactPublish?.blockers ?? []) { + if (isStaleLegacyIngressBlocker(blocker, report, reports)) { + continue; + } blockers.push(normalizeBlocker(blocker, report)); } for (const blocker of report.devDeployApply?.remainingBlockers ?? []) { + if (isStaleLegacyIngressBlocker(blocker, report, reports)) { + continue; + } blockers.push(normalizeBlocker(blocker, report)); } } @@ -487,6 +509,34 @@ function collectBlockers(reports) { return normalized.sort((a, b) => a.unblockOrder - b.unblockOrder || a.id.localeCompare(b.id)); } +function hasCurrentLiveEdgeEvidence(edgeReport) { + const publicHttp = edgeReport?.edgeHealth?.publicHttp ?? []; + return edgeReport?.edgeHealth?.endpoint === DEV_ENDPOINT && + edgeReport?.edgeHealth?.mode === "live-read-only" && + publicHttp.some((probe) => probe.url === `${DEV_ENDPOINT}/health` && probe.ok === true && probe.status === 200) && + publicHttp.some((probe) => probe.url === `${DEV_ENDPOINT}/health/live` && probe.ok === true && probe.status === 200); +} + +function isStaleLegacyIngressBlocker(blocker, sourceReport, reports) { + const text = `${blocker.scope ?? ""} ${blocker.summary ?? ""}`; + const staleLegacyPort = text.includes("74.48.78.17:6667"); + const stalePreflightEdgeProbe = sourceReport.path === reportPaths.devPreflight && + blocker.type === "network_blocker" && + (blocker.scope === "dev-edge" || blocker.scope === "dev-edge-health") && + ( + text.includes(`${DEV_ENDPOINT}/health/live is not reachable`) || + text.includes("live network probes require --live") + ); + + if (!staleLegacyPort && !stalePreflightEdgeProbe) { + return false; + } + const currentEdgeReachable = hasCurrentLiveEdgeEvidence(reports.devEdgeHealth); + return currentEdgeReachable && sourceReport.path !== reportPaths.devM3Hardware && + sourceReport.path !== reportPaths.devM4Agent && + sourceReport.path !== reportPaths.devM5Gate; +} + function deriveMilestones(evidence, blockers) { const evidenceByMilestone = new Map(); for (const item of evidence) { @@ -571,6 +621,7 @@ function buildDoD(reports, milestones, blockers) { const preflight = reports.devPreflight; const artifactIdentity = preflight.artifactIdentity; const d601 = reports.d601Observability; + const edgeLive = hasCurrentLiveEdgeEvidence(reports.devEdgeHealth); return { status: blockers.length === 0 && milestones.every((item) => item.status === "pass") ? "green" : "blocked", @@ -603,10 +654,12 @@ function buildDoD(reports, milestones, blockers) { : "D601 runner lacks kubectl/k3s/kubeconfig observability for hwlab-dev." }, { - id: "dev-edge-frp-6667", - status: hasBlocker(blockers, (blocker) => blocker.scope.includes("edge") || blocker.scope.includes("ingress") || blocker.summary.includes("6667")) ? "blocked" : "pass", - evidenceLevel: "BLOCKED", - summary: "No committed report proves live HTTP 200/JSON on http://74.48.78.17:16667." + id: "dev-edge-frp-16667", + status: edgeLive && !hasBlocker(blockers, isEdgeOrFrpBlocker) ? "pass" : "blocked", + evidenceLevel: edgeLive && !hasBlocker(blockers, isEdgeOrFrpBlocker) ? "DEV-LIVE" : "BLOCKED", + summary: edgeLive + ? "Committed edge report proves read-only public HTTP on :16667 /health and /health/live; old preflight network probe blockers are stale." + : "No committed report proves live HTTP 200/JSON on http://74.48.78.17:16667." }, { id: "cloud-api-db-ready", @@ -661,7 +714,7 @@ function actionForBlockerOrder(blockerOrder, items) { function fallbackAction(scope) { if (scope === "base-image") return "Preload or tag node:20-bookworm-slim and rerun the base-image and artifact publish preflights."; if (scope.includes("artifact")) return "Publish DEV artifacts for every frozen HWLAB service and record immutable registry digests."; - if (scope.includes("edge") || scope.includes("ingress")) return "Repair frp/master-edge/D601 router path and rerun read-only DEV edge health."; + 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 rerun health/preflight without exposing secrets."; if (scope.includes("kubectl") || scope.includes("k3s")) return "Provide read-only kubectl/kubeconfig observability for hwlab-dev."; return "Resolve the blocker and attach source/local/dry-run/DEV-live evidence at the correct level."; @@ -673,7 +726,7 @@ function evidenceRequiredFor(scope) { if (scope.includes("artifact") || scope === "ghcr") return "Artifact publish report with ciPublished=true, registryVerified=true, and sha256 digest for each frozen service ID."; 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 and redacted secret references, without secret material."; - if (scope.includes("edge") || scope.includes("ingress")) return "Read-only DEV route observation for :16667/frp/edge/router with HWLAB service identity and artifact identity."; + if (scope.includes("edge") || scope.includes("ingress") || scope.includes("frp")) return "Read-only DEV route observation for :16667/frp/edge/router with HWLAB service identity and artifact identity."; return "A committed report with the exact evidence level and command used."; } @@ -754,7 +807,7 @@ export async function buildReport() { green: dod.green, reason: dod.green ? "All #9 DEV DoD checks are green." - : "SOURCE, LOCAL, and DRY-RUN evidence exists, but DEV-LIVE acceptance is blocked by artifact, observability, DB, edge/frp, and loop evidence gaps." + : "SOURCE, LOCAL, DRY-RUN, and edge DEV-LIVE evidence exists, but acceptance is still blocked by artifact, observability, DB, and loop evidence gaps." }, dod, milestones, @@ -777,7 +830,9 @@ export function formatCheckSummary(report) { green: report.overall.green, blockers: report.blockers.length, nextStep: report.nextSteps[0]?.action ?? null, - levels + levels: Object.fromEntries( + Object.entries(report.levels).map(([level, entries]) => [level, entries.length]) + ) }; } diff --git a/scripts/validate-dev-gate-report.mjs b/scripts/validate-dev-gate-report.mjs index 94da72f4..13689ade 100644 --- a/scripts/validate-dev-gate-report.mjs +++ b/scripts/validate-dev-gate-report.mjs @@ -1433,7 +1433,12 @@ async function validateAggregatorV2Report(relativePath, report) { } assertArray(report.nextSteps, `${label}.nextSteps`); - assert.ok(report.nextSteps.length >= 5, `${label}.nextSteps must contain blocker order`); + assert.ok(report.nextSteps.length >= 1, `${label}.nextSteps must contain blocker order`); + assert.deepEqual( + report.nextSteps.map((step) => step.blockerOrder).sort((a, b) => a - b), + [...new Set(report.blockers.map((blocker) => blocker.unblockOrder))].sort((a, b) => a - b), + `${label}.nextSteps must cover active blocker orders` + ); assert.deepEqual( report.nextSteps.map((step) => step.order), [...report.nextSteps].map((step) => step.order).sort((a, b) => a - b), diff --git a/web/hwlab-cloud-web/gate-summary.mjs b/web/hwlab-cloud-web/gate-summary.mjs index a14cf236..6d3d786b 100644 --- a/web/hwlab-cloud-web/gate-summary.mjs +++ b/web/hwlab-cloud-web/gate-summary.mjs @@ -13,7 +13,7 @@ export const gateSummary = { "gateStatus": "blocked", "blocked": true, "acceptanceLevel": "dev_mvp_gate", - "reportCommitId": "6eb4c199b0c63cca7fd68fc3306f7a9cbe4323ea", + "reportCommitId": "86d769525caf1db513b93cb67c2c8ee8863dd4b1", "dryRunOnly": true, "devOnly": true, "prodDisabled": true, @@ -67,27 +67,44 @@ export const gateSummary = { }, "devPreconditions": { "status": "blocked", + "classification": "DB live; hardware loop", "requirements": [ - "Obtain a live HTTP 200/JSON health observation from http://74.48.78.17:16667/health and /live", - "Record live route observations for hwlab-edge-proxy, hwlab-tunnel-client, hwlab-router, hwlab-cloud-api/web, hwlab-gateway, hwlab-gateway-simu, hwlab-box-simu, hwlab-patch-panel, hwlab-agent-mgr, hwlab-agent-worker, and hwlab-agent-skills", + "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", + "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": [ - "curl -fsS --max-time 5 http://74.48.78.17:16667/health", - "curl -fsS --max-time 5 http://74.48.78.17:16667/live" + "curl -fsS --max-time 8 http://74.48.78.17:16666/", + "curl -fsS --max-time 8 http://74.48.78.17:16667/health/live", + "curl -fsS --max-time 8 http://74.48.78.17:16667/health", + "HWLAB_DEV_BOX_SIMU_1_URL=http://10.42.0.200:7201 HWLAB_DEV_BOX_SIMU_2_URL=http://10.42.0.208:7201 HWLAB_DEV_GATEWAY_SIMU_1_URL=http://10.42.0.209:7101 HWLAB_DEV_GATEWAY_SIMU_2_URL=http://10.42.0.204:7101 HWLAB_DEV_PATCH_PANEL_URL=http://10.42.0.205:7301 node scripts/dev-m3-hardware-loop-smoke.mjs --live --confirm-dev --confirmed-non-production", + "node scripts/dev-m4-agent-loop-smoke.mjs --live --confirm-dev --confirmed-non-production" ], "evidence": [ - "curl exit 7 for /health: could not connect to 74.48.78.17 port 16667", - "curl exit 7 for /live: could not connect to 74.48.78.17 port 16667" + "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", + "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" ], - "summary": "The frozen DEV endpoint is not reachable from this runner, so no live DEV gate can be claimed yet." + "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." }, "blockers": [ { - "type": "network_blocker", - "scope": "devPreconditions", + "type": "runtime_blocker", + "scope": "db-live", "status": "open", - "summary": "http://74.48.78.17:16667/health and /live both fail with curl exit 7; live DEV ingress evidence is missing." + "summary": "cloud-api /health/live reports DB degraded; db.ready=false, db.connected=false, and live DB evidence is not established." + }, + { + "type": "runtime_blocker", + "scope": "m3-hardware-loop-runtime", + "status": "open", + "summary": "Live M3 smoke reached DEV simulators, but patch-panel active DO1 -> DI1 connection is missing." } ], "milestones": [ @@ -114,24 +131,24 @@ export const gateSummary = { }, { "id": "M3", - "status": "pass", - "commandCount": 1, + "status": "blocked", + "commandCount": 2, "evidenceCount": 3, - "summary": "The local hardware trusted loop smoke passes." + "summary": "Local M3 remains green, but active DEV-LIVE M3 is blocked by hardware loop topology." }, { "id": "M4", - "status": "pass", - "commandCount": 1, - "evidenceCount": 1, - "summary": "The local agent automation loop smoke passes." + "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." }, { "id": "M5", - "status": "pass", + "status": "blocked", "commandCount": 3, - "evidenceCount": 3, - "summary": "The M5 orchestration is green in dry-run mode, but it stays fixture-only and does not claim live DEV readiness." + "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." } ], "artifactCount": 13,