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.
This commit is contained in:
Lyon
2026-05-22 13:15:31 +08:00
committed by GitHub
parent 7e29522b65
commit ab11565640
17 changed files with 590 additions and 530 deletions
+3 -2
View File
@@ -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.
+2 -2
View File
@@ -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.
+3 -1
View File
@@ -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";
+13 -13
View File
@@ -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": {
+24 -23
View File
@@ -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."
}
}
+11 -7
View File
@@ -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."
}
+172 -339
View File
@@ -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": [
+15 -22
View File
@@ -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
+89 -26
View File
@@ -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"
}
]
}
+32 -17
View File
@@ -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.
+7 -1
View File
@@ -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."
};
+104 -41
View File
@@ -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();
+3 -1
View File
@@ -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");
+2 -2
View File
@@ -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();
+66 -11
View File
@@ -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])
)
};
}
+6 -1
View File
@@ -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),
+38 -21
View File
@@ -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,