From 70bb9168ead272ec1f77b752df8e178e70858df4 Mon Sep 17 00:00:00 2001 From: HWLAB Code Queue Date: Thu, 21 May 2026 17:02:41 +0000 Subject: [PATCH] docs: add dev m5 gate report --- reports/dev-gate/dev-mvp-gate-report.json | 197 ++++++++++++++++++++++ reports/dev-gate/dev-mvp-gate-report.md | 46 +++++ scripts/validate-dev-gate-report.mjs | 73 +++++++- 3 files changed, 312 insertions(+), 4 deletions(-) create mode 100644 reports/dev-gate/dev-mvp-gate-report.json create mode 100644 reports/dev-gate/dev-mvp-gate-report.md diff --git a/reports/dev-gate/dev-mvp-gate-report.json b/reports/dev-gate/dev-mvp-gate-report.json new file mode 100644 index 00000000..cdd1a7c3 --- /dev/null +++ b/reports/dev-gate/dev-mvp-gate-report.json @@ -0,0 +1,197 @@ +{ + "$schema": "https://hwlab.pikastech.local/schemas/dev-gate-report.schema.json", + "$id": "https://hwlab.pikastech.local/reports/dev-gate/dev-mvp-gate-report.json", + "reportVersion": "v1", + "issue": "pikasTech/HWLAB#39", + "taskId": "dev-mvp-gate-report", + "commitId": "6eb4c199b0c63cca7fd68fc3306f7a9cbe4323ea", + "acceptanceLevel": "dev_mvp_gate", + "devOnly": true, + "prodDisabled": true, + "gateStatus": "blocked", + "sourceContract": { + "status": "pass", + "documents": [ + "docs/dev-gate-report.md", + "docs/dev-acceptance-matrix.md", + "docs/m0-contract-audit.md", + "docs/m1-local-smoke.md", + "docs/m2-dev-deploy-smoke.md", + "docs/m3-hardware-loop.md", + "docs/m4-agent-loop.md", + "docs/m5-mvp-e2e.md", + "docs/runtime-boundary-guard.md", + "docs/topology-constraints.md", + "docs/artifact-catalog.md", + "docs/schema-drift-map.md", + "protocol/README.md", + "protocol/audit.md", + "protocol/evidence-chain.md", + "protocol/mvp-e2e-contract.md" + ], + "summary": "The DEV gate is anchored to the frozen matrix, gate contract, and M0-M5 milestone docs on origin/main." + }, + "validationCommands": [ + "node --check scripts/validate-dev-gate-report.mjs", + "node scripts/validate-dev-gate-report.mjs" + ], + "localSmoke": { + "status": "pass", + "commands": [ + "node scripts/validate-contract.mjs", + "node scripts/validate-m0-contract.mjs", + "node scripts/validate-artifact-catalog.mjs", + "node scripts/validate-runtime-boundary.mjs", + "node scripts/validate-schema-drift-map.mjs", + "node scripts/validate-evidence-chain.mjs", + "node scripts/m1-contract-smoke.mjs", + "node scripts/m2-dev-deploy-smoke.mjs --dry-run", + "node scripts/m3-hardware-loop-smoke.mjs", + "node scripts/m4-agent-loop-smoke.mjs" + ], + "evidence": [ + "validated 15 JSON files and 13 service ids", + "validated M0 contract examples: 7 JSON files, 13 service ids", + "validated 13 DEV artifact catalog services at 24eb3bf", + "validated HWLAB runtime boundary guard for 13 services; forbidden substitutes: unidesk-backend, provider-gateway, microservice-proxy", + "validated schema drift map with 59 aligned fields and 12 gaps", + "validated 2 evidence chain fixtures and 2 evidence records", + "[m1-smoke] passed", + "[m2-smoke] validated 11 service contracts", + "[m2-smoke] mode=dry-run endpoint=http://74.48.78.17:6667", + "[m2-smoke] no real DEV/PROD request was made", + "M3 hardware loop smoke passed", + "[m4-smoke] ok m4-agent-automation-loop-local-contract-smoke" + ], + "summary": "M0-M4 contract and smoke checks pass locally without contacting the live DEV ingress." + }, + "dryRun": { + "status": "pass", + "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:6667, projects: 2", + "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" + ], + "summary": "The M5 orchestration dry-run is green, but it remains fixture-only and does not establish a live DEV gate." + }, + "devPreconditions": { + "status": "blocked", + "requirements": [ + "Obtain a live HTTP 200/JSON health observation from http://74.48.78.17:6667/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", + "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:6667/health", + "curl -fsS --max-time 5 http://74.48.78.17:6667/live" + ], + "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" + ], + "summary": "The frozen DEV endpoint is not reachable from this runner, so no live DEV gate can be claimed yet." + }, + "blockers": [ + { + "type": "network_blocker", + "scope": "devPreconditions", + "status": "open", + "summary": "http://74.48.78.17:6667/health and /live both fail with curl exit 7; live DEV ingress evidence is missing." + } + ], + "milestones": [ + { + "id": "M0", + "status": "pass", + "commands": [ + "node scripts/validate-contract.mjs", + "node scripts/validate-m0-contract.mjs", + "node scripts/validate-artifact-catalog.mjs", + "node scripts/validate-runtime-boundary.mjs", + "node scripts/validate-schema-drift-map.mjs", + "node scripts/validate-evidence-chain.mjs" + ], + "evidence": [ + "validated 15 JSON files and 13 service ids", + "validated M0 contract examples: 7 JSON files, 13 service ids", + "validated 13 DEV artifact catalog services at 24eb3bf", + "validated HWLAB runtime boundary guard for 13 services; forbidden substitutes: unidesk-backend, provider-gateway, microservice-proxy", + "validated schema drift map with 59 aligned fields and 12 gaps", + "validated 2 evidence chain fixtures and 2 evidence records" + ], + "summary": "Frozen contract, artifact, boundary, drift, and evidence fixtures are parseable and aligned to the DEV boundary." + }, + { + "id": "M1", + "status": "pass", + "commands": [ + "node scripts/m1-contract-smoke.mjs" + ], + "evidence": [ + "[m1-smoke] ok cloud-api health/live/rpc skeleton", + "[m1-smoke] ok patch-panel/sim status and route skeleton", + "[m1-smoke] ok CLI dry-run fixture parse", + "[m1-smoke] passed" + ], + "summary": "The local M1 contract smoke passes." + }, + { + "id": "M2", + "status": "pass", + "commands": [ + "node scripts/m2-dev-deploy-smoke.mjs --dry-run" + ], + "evidence": [ + "[m2-smoke] validated 11 service contracts", + "[m2-smoke] mode=dry-run endpoint=http://74.48.78.17:6667", + "[m2-smoke] no real DEV/PROD request was made" + ], + "summary": "The deploy smoke remains fixture-only and validates the frozen route phases and artifact metadata." + }, + { + "id": "M3", + "status": "pass", + "commands": [ + "node scripts/m3-hardware-loop-smoke.mjs" + ], + "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" + ], + "summary": "The local hardware trusted loop smoke passes." + }, + { + "id": "M4", + "status": "pass", + "commands": [ + "node scripts/m4-agent-loop-smoke.mjs" + ], + "evidence": [ + "[m4-smoke] ok m4-agent-automation-loop-local-contract-smoke" + ], + "summary": "The local agent automation loop smoke passes." + }, + { + "id": "M5", + "status": "pass", + "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:6667, projects: 2", + "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" + ], + "summary": "The M5 orchestration is green in dry-run mode, but it stays fixture-only and does not claim live DEV readiness." + } + ], + "notes": "Blocked gate report. Local contract, smoke, and dry-run checks pass on origin/main, but live DEV ingress is unreachable from this runner." +} diff --git a/reports/dev-gate/dev-mvp-gate-report.md b/reports/dev-gate/dev-mvp-gate-report.md new file mode 100644 index 00000000..771641dd --- /dev/null +++ b/reports/dev-gate/dev-mvp-gate-report.md @@ -0,0 +1,46 @@ +# HWLAB DEV M5 Gate Report + +Status: blocked + +Baseline: `6eb4c199b0c63cca7fd68fc3306f7a9cbe4323ea` +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:6667` is not reachable from this runner. + +## Evidence + +- `node scripts/validate-contract.mjs` +- `node scripts/validate-m0-contract.mjs` +- `node scripts/validate-artifact-catalog.mjs` +- `node scripts/validate-runtime-boundary.mjs` +- `node scripts/validate-schema-drift-map.mjs` +- `node scripts/validate-evidence-chain.mjs` +- `node scripts/m1-contract-smoke.mjs` +- `node scripts/m2-dev-deploy-smoke.mjs --dry-run` +- `node scripts/m3-hardware-loop-smoke.mjs` +- `node scripts/m4-agent-loop-smoke.mjs` +- `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:6667/health` +- `curl -fsS --max-time 5 http://74.48.78.17:6667/live` + +## Result + +- `M0`: pass +- `M1`: pass +- `M2`: pass +- `M3`: pass +- `M4`: pass +- `M5`: pass +- `overall`: blocked + +## Minimal Next Step + +Obtain live `200`/JSON health observations from `http://74.48.78.17:6667/health` and `/live`, then capture the live route observations for the DEV ingress chain without switching to PROD or heavy e2e. + +## Blocker + +The frozen DEV endpoint returns connection failures from this runner, so no live DEV ingress evidence can be claimed yet. diff --git a/scripts/validate-dev-gate-report.mjs b/scripts/validate-dev-gate-report.mjs index 13d4f896..ec01e65b 100644 --- a/scripts/validate-dev-gate-report.mjs +++ b/scripts/validate-dev-gate-report.mjs @@ -8,8 +8,24 @@ import { fileURLToPath } from "node:url"; const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const reportsDir = path.join(repoRoot, "reports/dev-gate"); -const allowedIssues = new Set(["pikasTech/HWLAB#31", "pikasTech/HWLAB#33", "pikasTech/HWLAB#36"]); -const requiredPreflightIssue = "pikasTech/HWLAB#34"; +const contractIssue = "pikasTech/HWLAB#31"; +const issueFamily = Object.freeze({ + DEV_DEPLOY_APPLY: "pikasTech/HWLAB#33", + DEV_GATE_PREFLIGHT: "pikasTech/HWLAB#34", + DEV_ARTIFACT_PUBLISH: "pikasTech/HWLAB#35", + DEV_EDGE_HEALTH: "pikasTech/HWLAB#36", + DEV_M4_AGENT_LOOP: "pikasTech/HWLAB#37", + DEV_M3_HARDWARE_LOOP: "pikasTech/HWLAB#38", + DEV_M5_GATE_REPORT: "pikasTech/HWLAB#39", + DEV_BASE_IMAGE_PREFLIGHT: "pikasTech/HWLAB#40", + DEV_EVIDENCE_BLOCKER_AGGREGATOR: "pikasTech/HWLAB#41" +}); +const allowedIssues = new Set([ + contractIssue, + ...Object.values(issueFamily) +]); +const requiredPreflightIssue = issueFamily.DEV_GATE_PREFLIGHT; +const requiredMilestoneIds = ["M0", "M1", "M2", "M3", "M4", "M5"]; const requiredValidationCommands = [ "node --check scripts/validate-dev-gate-report.mjs", "node scripts/validate-dev-gate-report.mjs" @@ -26,7 +42,7 @@ const requiredDocs = [ "docs/dev-acceptance-matrix.md", "docs/m0-contract-audit.md" ]; -const requiredDevM3Issue = "pikasTech/HWLAB#38"; +const requiredDevM3Issue = issueFamily.DEV_M3_HARDWARE_LOOP; const requiredDevM3ValidationCommands = [ "node --check scripts/dev-m3-hardware-loop-smoke.mjs", "node scripts/dev-m3-hardware-loop-smoke.mjs --live --confirm-dev --confirmed-non-production" @@ -35,7 +51,7 @@ const requiredDevM3Docs = [ "docs/dev-acceptance-matrix.md", "docs/m3-hardware-loop.md" ]; -const requiredDevEdgeIssue = "pikasTech/HWLAB#36"; +const requiredDevEdgeIssue = issueFamily.DEV_EDGE_HEALTH; const requiredDevEdgeValidationCommands = [ "node --check scripts/dev-edge-health-smoke.mjs", "node --check scripts/src/dev-edge-health-smoke-lib.mjs", @@ -259,6 +275,55 @@ async function validateReport(relativePath) { if (Object.hasOwn(report, "notes")) { assertString(report.notes, `${label}.notes`); } + + if (Object.hasOwn(report, "gateStatus")) { + assertStatus(report.gateStatus, `${label}.gateStatus`); + } + + if (Object.hasOwn(report, "milestones")) { + assertArray(report.milestones, `${label}.milestones`); + assert.deepEqual( + report.milestones.map((milestone) => milestone.id), + requiredMilestoneIds, + `${label}.milestones must cover M0-M5 in order` + ); + assertUnique( + report.milestones.map((milestone) => milestone.id), + `${label}.milestones` + ); + + for (const [index, milestone] of report.milestones.entries()) { + const milestoneLabel = `${label}.milestones[${index}]`; + assertObject(milestone, milestoneLabel); + for (const field of ["id", "status", "commands", "evidence", "summary"]) { + assert.ok(Object.hasOwn(milestone, field), `${milestoneLabel} missing ${field}`); + } + assert.match(milestone.id, /^M[0-5]$/, `${milestoneLabel}.id`); + assertStatus(milestone.status, `${milestoneLabel}.status`); + assertStringArray(milestone.commands, `${milestoneLabel}.commands`, { minLength: 1 }); + assertUnique(milestone.commands, `${milestoneLabel}.commands`); + assertStringArray(milestone.evidence, `${milestoneLabel}.evidence`, { minLength: 1 }); + assertUnique(milestone.evidence, `${milestoneLabel}.evidence`); + assertString(milestone.summary, `${milestoneLabel}.summary`); + if (Object.hasOwn(milestone, "blocker")) { + assertString(milestone.blocker, `${milestoneLabel}.blocker`); + } + } + } + + if (Object.hasOwn(report.devPreconditions, "commands")) { + assertStringArray(report.devPreconditions.commands, `${label}.devPreconditions.commands`, { + minLength: 1 + }); + assertUnique(report.devPreconditions.commands, `${label}.devPreconditions.commands`); + } + + if (Object.hasOwn(report.devPreconditions, "evidence")) { + assertStringArray(report.devPreconditions.evidence, `${label}.devPreconditions.evidence`, { + minLength: 1 + }); + assertUnique(report.devPreconditions.evidence, `${label}.devPreconditions.evidence`); + } } async function assertDocumentSet(documentsValue, label, requiredDocs) {