# HWLAB DEV Acceptance Matrix This matrix is the DEV acceptance contract for the MVP runtime. It is scoped to static review and lightweight smoke checks only. It does not authorize a real DEV or PROD deployment. ## Fixed Boundary - DEV frontend endpoint: `http://74.48.78.17:16666` - DEV API/edge endpoint: `http://74.48.78.17:16667` - Deploy environment: `dev` - Legacy public endpoints `:6666` and `:6667` are deprecated; browser entry is `:16666` and API/health entry is `:16667`. - Internal k3s service ports may still use `6667`, for example `hwlab-cloud-api` and `hwlab-edge-proxy`. Internal `6667` is not a public DEV acceptance endpoint. - Runtime route: client, master `hwlab-edge-proxy`, `frp`, D601 `hwlab-dev/hwlab-router`, then HWLAB cloud/runtime services. - UniDesk backend, provider-gateway, and microservice proxy are not accepted as substitutes for HWLAB runtime services in this first version. They may remain external scheduling, CI, or CD support only. ## M3 Evidence Classification Current P0 DEV acceptance remains the M3 virtual hardware trusted loop: two `hwlab-box-simu` instances, two `hwlab-gateway-simu` instances, and one `hwlab-patch-panel`. `M3 live` can be claimed only when a DEV observation proves the live `res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1` path and records the operation, trace, audit, and evidence identifiers. The patch panel must own the route decision; direct box-to-box propagation or fixture output is not M3 live evidence. `M3 support` includes this endpoint freeze, read-only public edge curl evidence, source contracts, static manifest cardinality, local smoke output, and dry-run fixtures. These items support release or pre-release decisions, but they are not P0 live acceptance. `Non-P0` includes SOURCE, LOCAL, DRY-RUN, fixture-only, diagnostic, and edge-only observations that do not prove the full `res_boxsimu_1 -> hwlab-patch-panel -> res_boxsimu_2` link. These observations must not be written as `DEV-LIVE`. ## Required Artifact Observability Every deployable HWLAB artifact that participates in DEV acceptance must expose or be joined with these fields: | Field | Requirement | | --- | --- | | `serviceId` | One of the frozen HWLAB service IDs. | | `commitId` | Git commit that produced the artifact, short or full SHA. | | `image` | Image repository/name when containerized, or package artifact name for non-container artifacts. | | `tag` | Immutable or traceable tag, preferably including the commit. | | `digest` | Content digest when the artifact is an image or build output that supports digests. | | `buildSource` | Source repository, branch/ref, and build workflow or local command. | | `deployEnv` | Must be `dev` for this matrix. | | `healthTimestamp` | ISO-8601 timestamp from the health observation or smoke collector. | Missing `digest` is allowed only for non-container client assets or local dry-run artifacts, and must be recorded as `not_applicable` with a reason. ## Health Contract All health responses must be JSON, include `serviceId`, identify `dev`, and provide a current health timestamp. Existing skeleton services may expose `observedAt`; the acceptance collector maps it to `healthTimestamp`. | Component | Service ID | Check | Success | Failure | | --- | --- | --- | --- | --- | | DEV API/edge ingress | `hwlab-edge-proxy` | `GET http://74.48.78.17:16667/health` or routed service health | HTTP 2xx/3xx reaches HWLAB DEV path and reports edge identity or downstream HWLAB identity | Timeout, non-HWLAB response, PROD route, missing artifact fields | | master edge proxy | `hwlab-edge-proxy` | Edge proxy health and route table observation | Route for `http://74.48.78.17:16667` forwards to `frp` and identifies commit/image | No DEV route, wrong port, missing route observability | | frp tunnel | `hwlab-tunnel-client` | Tunnel session/status observation | Tunnel for DEV route is established to D601 router and identifies commit/image | Tunnel down, wrong target, ambiguous service identity | | D601 router | `hwlab-router` | `hwlab-dev/hwlab-router` health/status | Router is live, environment is `dev`, route target is cloud API/web or runtime service | Namespace mismatch, route missing, stale health timestamp | | Cloud API | `hwlab-cloud-api` | `GET /health`, `GET /live`, optional JSON-RPC `/rpc` probe | Returns service ID, `dev`, healthy/live status, redacted DB env readiness, and accepts a harmless protocol probe | HTTP error, unknown service ID, wrong environment, invalid JSON-RPC envelope, missing DB env readiness | | Cloud Web | `hwlab-cloud-web` | `GET http://74.48.78.17:16666/`, static asset check, and the workbench contract in `docs/cloud-web-workbench.md` | Public browser entry serves the Cloud Workbench on `:16666`; default page is a VS Code-style workbench with left activity rail/resource tree, center Agent conversation/trace, right hardware/evidence side panel, and bottom command/input area; API/edge status remains on `http://74.48.78.17:16667`; browser data uses same-origin `/v1`, read-only `/json-rpc`, source/gate report, and blocked report with explicit `sourceKind` labels | Endpoint drift, public web served from `:6667`, Gate/M3 Diagnostics used as default homepage, direct write/control endpoint text or calls, missing `SOURCE`/`DRY-RUN`/`DEV-LIVE`/`BLOCKED` labeling, edge-only evidence presented as M3 `DEV-LIVE`, missing asset | | Agent manager | `hwlab-agent-mgr` | Agent scheduling health/status | Reports live manager, commit/image, and DEV environment; no worker leak after smoke | Scheduler unavailable, wrong environment, unbounded worker session | | Agent worker | `hwlab-agent-worker` | Worker health/status during dry-run or scoped smoke | Worker session is scoped to DEV project and emits trace/audit identifiers | Missing session identity, unsafe mutation, cleanup failure | | Agent skills | `hwlab-agent-skills` | Skill bundle version/status | Skill artifact is traceable to commit/build source and compatible with worker | Unversioned skill bundle, missing build source | | Gateway | `hwlab-gateway` | `GET /health/live` and `GET /status` when present | Reports DEV gateway boundary and does not bypass patch-panel constraints | Hardware boundary unavailable, non-DEV gateway, direct box mutation | | Gateway simulator | `hwlab-gateway-simu` | `GET /health/live`, `GET /status`, `GET /boxes` | Simulator is live, lists expected box resources, and identifies DEV project; this is M3 support until paired with the full patch-panel link observation | Simulator down, box list missing, stale timestamp | | Box simulator | `hwlab-box-simu` | `GET /health/live`, `GET /status` | Simulator is live and reports resources, ports, and patch-panel-only propagation; this is M3 support until paired with the full patch-panel link observation | Cross-device propagation outside patch panel, missing resource state | | Patch panel | `hwlab-patch-panel` | `GET /health/live`, `GET /status`, `GET /wiring` | Wiring config is parseable and patch-panel state owns routing decisions; M3 live also requires a traced `DO1 -> patch-panel -> DI1` operation | Invalid topology, direct bypass path, stale patch state | | CLI | `hwlab-cli` | `npm run cli:health` and dry-run command | CLI uses DEV endpoint and dry-run states no DEV/PROD changes were made | Wrong endpoint, missing dry-run guard, real mutation attempted | ## DEV Smoke Matrix The smoke sequence must run in order and stop on the first critical blocker. Network checks may be replaced by recorded observations when the runner cannot reach the DEV host, but replacement evidence must include the artifact fields listed above. Cloud Web workbench smoke is covered by: - `node scripts/dev-cloud-workbench-smoke.mjs --static` - `node scripts/dev-cloud-workbench-smoke.mjs --live --url http://74.48.78.17:16666/` The static mode is SOURCE-level contract evidence only and must report `devLive=false`; it cannot promote SOURCE, LOCAL, DRY-RUN, or fixture evidence to DEV-LIVE. It observes the PR #114 Markdown help surface as ready when `web/hwlab-cloud-web/help.md`, the vendored `marked` renderer, and the non-default internal help route are present. The live mode is optional read-only HTTP plus browser DOM observation and must report `blocked` or `skip` structure instead of a false green when the browser check is unavailable. | Step | Probe | Success Criteria | Failure Criteria | Blocker Class | | --- | --- | --- | --- | --- | | 1 | Confirm repository contract files and JSON checklist parse. | `docs/dev-acceptance-matrix.md` exists and `docs/dev-acceptance-checklist.json` parses. | Missing file or invalid JSON. | `contract_blocker` | | 2 | Verify frozen DEV endpoints. | Public frontend is exactly `http://74.48.78.17:16666`; public API/edge is exactly `http://74.48.78.17:16667`; internal `6667` appears only as a k3s service/listen port. | Any alternate public DEV endpoint, old public `:6667`, or PROD target. | `environment_blocker` | | 3 | Observe DEV API/edge ingress health. | Request reaches HWLAB DEV route and returns HWLAB identity or accepted downstream health. | Timeout, non-HWLAB target, wrong public port. | `network_blocker` | | 4 | Observe master edge proxy route. | Edge route maps DEV endpoint to `frp` and records artifact identity. | Missing route, stale route, missing artifact identity. | `network_blocker` | | 5 | Observe `frp` tunnel. | Tunnel links master edge to D601 router for DEV. | Tunnel down or target mismatch. | `network_blocker` | | 6 | Observe D601 `hwlab-dev/hwlab-router`. | Router is live and forwards only to HWLAB DEV services. | Namespace mismatch or route bypass. | `runtime_blocker` | | 7 | Check cloud API/web surface. | Cloud API health is valid on public `:16667`; web assets are served on public `:16666`; Cloud Web default route is the Cloud Workbench defined in `docs/cloud-web-workbench.md`; diagnostics/status/gate are secondary; data sources are same-origin `/v1`, read-only `/json-rpc`, source/gate report, and blocked report; `npm run web:m3-readonly` or its workbench-aware successor passes. | Bad health, endpoint drift, Gate/M3 Diagnostics used as default homepage, direct hardware write/control surface from web, missing source labels, or edge-only evidence promoted to M3 `DEV-LIVE`. | `runtime_blocker` | | 8 | Check gateway, simulator, box simulator, and patch-panel contracts. | Health/status JSON is parseable and topology keeps routing under patch-panel ownership; for M3 live, a traced `DO1 -> patch-panel -> DI1` operation exists. | Missing health, invalid topology, bypass path, or any attempt to promote support/fixture evidence to M3 live. | `runtime_blocker` | | 9 | Check agent manager, worker, and skills contracts. | Agent artifacts are traceable; dry-run/scoped smoke emits session, trace, audit, and cleanup evidence. | Missing traceability, unsafe mutation, cleanup leak. | `agent_blocker` | | 10 | Verify evidence and artifact observability. | Every accepted artifact has service ID, commit, image/tag/digest or reason, build source, env, and health timestamp. | Missing required observability field. | `observability_blocker` | ## Pass And Fail Rules The matrix passes only when every smoke step is either observed as successful or explicitly marked not applicable with a non-production reason. A step is failed when the observed result contradicts a frozen contract, cannot be parsed, or cannot be tied to a traceable HWLAB artifact. M3 live cannot be inferred from SOURCE, LOCAL, DRY-RUN, edge-only, or front-end-only evidence. If the evidence does not show the operation, trace, audit, and evidence IDs on the `res_boxsimu_1 -> hwlab-patch-panel -> res_boxsimu_2` chain, it is not a pass. Critical blockers are `contract_blocker`, `environment_blocker`, `network_blocker`, `runtime_blocker`, `agent_blocker`, `observability_blocker`, and `safety_blocker`. A `safety_blocker` must be raised for any attempted PROD deployment, real deployment from this matrix, secret read, heavyweight e2e run, or UniDesk runtime substitution. ## First Version Exclusions - No PROD deployment or PROD smoke. - No real DEV deployment from this document. - No heavyweight e2e or destructive hardware action. - No secret or token reads. - No replacement of HWLAB runtime services by UniDesk backend, provider-gateway, or microservice proxy.