fix: freeze dev ports and edge health

This commit is contained in:
lyon
2026-05-22 11:16:29 +08:00
parent b1f4e6e52d
commit 59bd0a36fa
42 changed files with 169 additions and 132 deletions
+7 -2
View File
@@ -27,7 +27,12 @@ function proxyDetails() {
const server = createServer((request, response) => {
const url = new URL(request.url || "/", "http://hwlab-edge-proxy.local");
if (request.method === "GET" && (url.pathname === "/health" || url.pathname === "/health/live")) {
if (request.method === "GET" && url.pathname === "/health/live") {
proxyHttpRequest({ request, response, upstream });
return;
}
if (request.method === "GET" && (url.pathname === "/health" || url.pathname === "/edge/health")) {
sendJson(response, 200, healthPayload({
serviceId,
role: "public-dev-ingress",
@@ -56,7 +61,7 @@ const server = createServer((request, response) => {
if (request.method === "GET" && url.pathname === "/help") {
sendJson(response, 200, {
serviceId,
commands: ["GET /health", "GET /health/live", "GET /status", "GET /routes"]
commands: ["GET /health", "GET /edge/health", "GET /health/live", "GET /status", "GET /routes"]
});
return;
}
+3 -1
View File
@@ -9,7 +9,8 @@ import {
const serviceId = "hwlab-tunnel-client";
const mode = process.env.HWLAB_TUNNEL_MODE || "frp-client";
const serverAddress = process.env.HWLAB_FRP_SERVER_ADDR || "74.48.78.17";
const publicPort = parsePort(process.env.HWLAB_FRP_PUBLIC_PORT, 6667);
const publicPort = parsePort(process.env.HWLAB_FRP_PUBLIC_PORT, 16667);
const webPublicPort = parsePort(process.env.HWLAB_FRP_WEB_PUBLIC_PORT, 16666);
const localService = process.env.HWLAB_TUNNEL_LOCAL_SERVICE || "hwlab-edge-proxy";
const localPort = parsePort(process.env.HWLAB_TUNNEL_LOCAL_PORT, 6667);
const { host, port } = resolveHostPort({
@@ -29,6 +30,7 @@ function tunnelState() {
direction: "d601-to-master",
serverAddress,
publicPort,
webPublicPort,
localService,
localPort
},
+2 -2
View File
@@ -3,7 +3,7 @@
`deploy.schema.json` defines the future `deploy/deploy.json` manifest shape.
The MVP acceptance environment is DEV only, with endpoint
`http://74.48.78.17:6667`. PROD profile fields may be represented in schema for
`http://74.48.78.17:16667`. PROD profile fields may be represented in schema for
future compatibility, but PROD deployment is not part of MVP acceptance.
## L5 DEV Skeleton
@@ -27,7 +27,7 @@ Next DEV deploy smoke commands, for a separately authorized deployment task:
npm run check
node -e "JSON.parse(require('node:fs').readFileSync('deploy/deploy.json','utf8'))"
kubectl apply --dry-run=server -k deploy/k8s/dev
curl -fsS http://74.48.78.17:6667/health/live
curl -fsS http://74.48.78.17:16667/health/live
node scripts/dev-edge-health-smoke.mjs --live --write-report
```
+1 -1
View File
@@ -25,7 +25,7 @@
},
"endpoint": {
"type": "string",
"const": "http://74.48.78.17:6667"
"const": "http://74.48.78.17:16667"
},
"profiles": {
"type": "object",
+5 -4
View File
@@ -2,11 +2,12 @@
The DEV reverse link is D601 to master edge through frp.
- Public DEV endpoint: `http://74.48.78.17:6667`
- Public DEV endpoint: `http://74.48.78.17:16667`
- `hwlab-tunnel-client` owns the frp client health contract.
- `hwlab-edge-proxy` owns public HTTP ingress on port `6667`.
- `frps.dev.toml` reserves `6667` only as a TCP `remotePort`; do not also bind
it as `vhostHTTPPort`, because that collides with the DEV TCP proxy.
- `hwlab-cloud-web` owns the public browser entry on port `16666`.
- `hwlab-edge-proxy` owns public API/health ingress on port `16667`.
- `frps.dev.toml` reserves `16666` and `16667` only as TCP `remotePort` values; do not also bind
them as `vhostHTTPPort`, because that collides with the DEV TCP proxy.
- No secret values are stored in this repository. Operators must provide auth
material out of band before a real deployment.
- UniDesk backend, provider-gateway, and microservice proxy are not HWLAB runtime
+8 -1
View File
@@ -2,12 +2,19 @@ serverAddr = "74.48.78.17"
serverPort = 7000
loginFailExit = true
[[proxies]]
name = "hwlab-dev-cloud-web"
type = "tcp"
localIP = "hwlab-cloud-web.hwlab-dev.svc.cluster.local"
localPort = 8080
remotePort = 16666
[[proxies]]
name = "hwlab-dev-edge-proxy"
type = "tcp"
localIP = "hwlab-edge-proxy.hwlab-dev.svc.cluster.local"
localPort = 6667
remotePort = 6667
remotePort = 16667
[[proxies]]
name = "hwlab-dev-tunnel-health"
+6 -2
View File
@@ -1,8 +1,12 @@
bindPort = 7000
[[allowPorts]]
start = 6667
end = 6667
start = 16666
end = 16666
[[allowPorts]]
start = 16667
end = 16667
[[allowPorts]]
start = 7402
+1 -1
View File
@@ -10,7 +10,7 @@
}
},
"data": {
"endpoint": "http://74.48.78.17:6667",
"endpoint": "http://74.48.78.17:16667",
"cloud-api": "GET /health/live via hwlab-edge-proxy then hwlab-cloud-api:6667",
"cloud-api-db": "DEV DB config gate requires HWLAB_CLOUD_DB_URL from Secret hwlab-cloud-api-dev-db/database-url plus HWLAB_CLOUD_DB_SSL_MODE=require; health reports only env presence and redacted Secret reference names, not live DB evidence",
"cloud-web": "GET /health/live on hwlab-cloud-web:8080; consumes cloud-api only",
+1 -1
View File
@@ -3,7 +3,7 @@
The master edge exposes only the DEV acceptance endpoint for this skeleton:
```text
http://74.48.78.17:6667
http://74.48.78.17:16667
```
Health ownership:
+3 -2
View File
@@ -1,12 +1,13 @@
{
"environment": "dev",
"endpoint": "http://74.48.78.17:6667",
"endpoint": "http://74.48.78.17:16667",
"reverseLink": {
"mode": "frp",
"direction": "d601-to-master",
"client": "hwlab-tunnel-client",
"serverAddress": "74.48.78.17",
"publicPort": 6667
"publicPort": 16667,
"webPublicPort": 16666
},
"contracts": [
{
+1 -1
View File
@@ -23,7 +23,7 @@ metadata, then be copied into the catalog by the refresh command below.
- Environment: DEV only.
- Namespace: `hwlab-dev`.
- Public DEV endpoint: `http://74.48.78.17:6667`.
- Public DEV endpoint: `http://74.48.78.17:16667`.
- Profile: `dev`.
- Health path: `/health/live`.
- Artifact state: contract skeleton only.
+6 -6
View File
@@ -4,7 +4,7 @@
"matrixVersion": "v1",
"issue": "pikasTech/HWLAB#22",
"environment": "dev",
"endpoint": "http://74.48.78.17:6667",
"endpoint": "http://74.48.78.17:16667",
"runtimeSubstitutePolicy": {
"allowedExternalRoles": [
"scheduling",
@@ -40,7 +40,7 @@
"id": "dev-endpoint",
"label": "DEV endpoint",
"serviceId": "hwlab-edge-proxy",
"endpoint": "http://74.48.78.17:6667",
"endpoint": "http://74.48.78.17:16667",
"role": "public-dev-ingress"
},
{
@@ -78,7 +78,7 @@
"serviceId": "hwlab-edge-proxy",
"probe": {
"method": "GET",
"url": "http://74.48.78.17:6667/health"
"url": "http://74.48.78.17:16667/health"
},
"requiredFields": [
"serviceId",
@@ -93,7 +93,7 @@
"serviceId": "hwlab-edge-proxy",
"probe": {
"type": "route-observation",
"target": "http://74.48.78.17:6667"
"target": "http://74.48.78.17:16667"
},
"requiredFields": [
"serviceId",
@@ -343,14 +343,14 @@
"id": "endpoint-freeze",
"order": 2,
"probe": "Compare documented and fixture DEV endpoints.",
"successCriteria": "All DEV endpoints equal http://74.48.78.17:6667.",
"successCriteria": "All DEV endpoints equal http://74.48.78.17:16667.",
"failureCriteria": "Any alternate DEV endpoint or PROD target.",
"blockerClass": "environment_blocker"
},
{
"id": "dev-ingress-health",
"order": 3,
"probe": "Observe GET http://74.48.78.17:6667/health or recorded equivalent.",
"probe": "Observe GET http://74.48.78.17:16667/health or recorded equivalent.",
"successCriteria": "Request reaches HWLAB DEV route and returns HWLAB identity or accepted downstream health.",
"failureCriteria": "Timeout, non-HWLAB target, or wrong port.",
"blockerClass": "network_blocker"
+6 -6
View File
@@ -6,9 +6,9 @@ DEV or PROD deployment.
## Fixed Boundary
- DEV endpoint: `http://74.48.78.17:6667`
- DEV endpoint: `http://74.48.78.17:16667`
- Deploy environment: `dev`
- PROD endpoint `:6666` is reserved and must not be targeted by this matrix.
- Legacy endpoint `:6666` is deprecated; browser entry is `:16666` and API/health entry is `:16667`.
- 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
@@ -42,12 +42,12 @@ provide a current health timestamp. Existing skeleton services may expose
| Component | Service ID | Check | Success | Failure |
| --- | --- | --- | --- | --- |
| DEV ingress | `hwlab-edge-proxy` | `GET http://74.48.78.17:6667/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:6667` forwards to `frp` and identifies commit/image | No DEV route, wrong port, missing route observability |
| DEV 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` | Static asset check and configured DEV endpoint | Web bundle references `http://74.48.78.17:6667` and does not call hardware directly | Endpoint drift, direct hardware control path, missing asset |
| Cloud Web | `hwlab-cloud-web` | Static asset check and configured DEV endpoint | Web bundle references `http://74.48.78.17:16667` and does not call hardware directly | Endpoint drift, direct hardware control path, 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 |
@@ -67,7 +67,7 @@ listed above.
| 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 endpoint. | Endpoint is exactly `http://74.48.78.17:6667` in docs/checklist/runtime fixtures. | Any alternate DEV endpoint or PROD target. | `environment_blocker` |
| 2 | Verify frozen DEV endpoint. | Endpoint is exactly `http://74.48.78.17:16667` in docs/checklist/runtime fixtures. | Any alternate DEV endpoint or PROD target. | `environment_blocker` |
| 3 | Observe DEV ingress health. | Request reaches HWLAB DEV route and returns HWLAB identity or accepted downstream health. | Timeout, non-HWLAB target, wrong 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` |
+1 -1
View File
@@ -98,7 +98,7 @@ The current `origin/main` deploy contract is blocked for real DEV apply:
current source commit validated for this apply (`1e8d009e9531`).
- The runner does not provide `kubectl`, so it cannot read or apply the D601
`hwlab-dev` namespace.
- The public DEV health probe at `http://74.48.78.17:6667/health/live` is not
- The public DEV health probe at `http://74.48.78.17:16667/health/live` is not
reachable from this runner.
- `hwlab-cloud-api` now has a DEV DB env contract placeholder:
`HWLAB_CLOUD_DB_URL` must come from Secret reference
+6 -6
View File
@@ -12,7 +12,7 @@ HWLAB runtime.
## Health Evidence
`GET http://74.48.78.17:6667/health` must return HWLAB DEV JSON with:
`GET http://74.48.78.17:16667/health` must return HWLAB DEV JSON with:
- `serviceId` for the HWLAB service answering the request;
- `environment: "dev"`;
@@ -44,9 +44,9 @@ present but no live DB probe is connected, `db.status` remains `"degraded"` and
The smoke classifies failures into these blockers:
- `frp_blocker`: public `:6667` is unavailable and frps control or tunnel
- `frp_blocker`: public `:16667` is unavailable and frps control or tunnel
health ports also refuse connections.
- `edge_proxy_blocker`: frps is reachable, but public `:6667` refuses.
- `edge_proxy_blocker`: frps is reachable, but public `:16667` refuses.
- `k3s_service_blocker`: k3s is observable but HWLAB DEV services/endpoints are
missing.
- `dns_port_firewall_blocker`: public endpoint times out or cannot be resolved
@@ -71,7 +71,7 @@ Blocked `frp_blocker` and `edge_proxy_blocker` reports now include a
The committed report at `reports/dev-gate/dev-edge-health.json` records a
read-only live run where:
- public `74.48.78.17:6667` returned `ECONNREFUSED`;
- public `74.48.78.17:16667` returned `ECONNREFUSED`;
- frps control `74.48.78.17:7000` returned `ECONNREFUSED`;
- tunnel health `74.48.78.17:7402` returned `ECONNREFUSED`;
- `kubectl` was not installed in this runner, so D601 k3s service state was not
@@ -83,7 +83,7 @@ the public DEV route yet.
## DEV FRP Contract
`deploy/frp/frps.dev.toml` reserves public `6667` as a TCP `remotePort` for
`hwlab-dev-edge-proxy`. Do not bind `vhostHTTPPort = 6667` in the same frps
`deploy/frp/frps.dev.toml` reserves public `16666` for `hwlab-cloud-web` and
public `16667` as a TCP `remotePort` for `hwlab-dev-edge-proxy`. Do not bind `vhostHTTPPort = 16667` in the same frps
config; that collides with the TCP proxy and can keep the DEV route from
registering cleanly.
+1 -1
View File
@@ -83,7 +83,7 @@ The JSON output groups recommended next actions in dependency order:
4. `cloud-api-db`: prove DEV cloud-api DB env and health readiness with
redacted values only.
5. `dev-edge`, `dev-edge-health`, `dev-ingress-health`: repair
`:6667`/frp/edge/router reachability, then rerun read-only DEV edge health
`:16667`/frp/edge/router reachability, then rerun read-only DEV edge health
before M3/M4/M5 live loops.
## Boundaries
+1 -1
View File
@@ -61,7 +61,7 @@ The preflight checks:
- 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.
- `http://74.48.78.17:6667/health/live` responds.
- `http://74.48.78.17:16667/health/live` responds.
- GHCR manifests are visible without reading credentials.
- Deploy images do not point at UniDesk, provider-gateway, or microservice-proxy
substitutes.
+1 -1
View File
@@ -8,7 +8,7 @@ This document records the DEV-only M4 agent loop smoke for
- Verify the agent manager, worker workspace, explicit skills commit
injection, trace/evidence chain, and cleanup behavior.
- Keep the runtime path on the fixed DEV boundary at
`http://74.48.78.17:6667`.
`http://74.48.78.17:16667`.
- Avoid secret reads, PROD access, long-running agent tasks, and direct gateway
access.
+1 -1
View File
@@ -6,7 +6,7 @@ the referenced #7/#11/#12/#16 guardrails.
Applied constraints:
- MVP acceptance is DEV only at `http://74.48.78.17:6667`.
- MVP acceptance is DEV only at `http://74.48.78.17:16667`.
- PROD is reserved and must not be deployed for this audit.
- HWLAB runtime services must keep their frozen service IDs and must not be
replaced by UniDesk services.
+1 -1
View File
@@ -38,7 +38,7 @@ npm run m1:smoke
This smoke is not the future DEV e2e acceptance test. It intentionally does not:
- deploy to DEV or PROD;
- call `http://74.48.78.17:6667`;
- call `http://74.48.78.17:16667`;
- run browser e2e;
- read secrets, tokens, kubeconfig, tunnel credentials, or deploy manifests;
- validate real gateway, router, frp, edge proxy, agent, worker, or hardware
+1 -1
View File
@@ -43,7 +43,7 @@ node scripts/m2-dev-deploy-smoke.mjs --live --confirm-dev --confirmed-non-produc
Before using `--live`, confirm all of the following:
- the target remains `http://74.48.78.17:6667`;
- the target remains `http://74.48.78.17:16667`;
- the workspace is not a PROD or shared deployment context;
- no prohibited action is being attempted;
- the request is observational only and does not mutate runtime state.
+1 -1
View File
@@ -79,7 +79,7 @@ node scripts/dev-m3-hardware-loop-smoke.mjs --live --confirm-dev --confirmed-non
```
The smoke writes `reports/dev-gate/dev-m3-hardware-loop.json`. It first checks
the frozen DEV endpoint, `http://74.48.78.17:6667`, and stops at the first
the frozen DEV endpoint, `http://74.48.78.17:16667`, and stops at the first
critical blocker from `docs/dev-acceptance-matrix.md`. When DEV ingress is not
observable, the report is `blocked` and the script does not run the live
`do.write true -> di.read true` operation.
+1 -1
View File
@@ -76,7 +76,7 @@ Do not switch to the real command until all of these are true:
1. `node scripts/m5-mvp-e2e-dry-run.mjs` passes on `origin/main`.
2. `docs/dev-acceptance-checklist.json` and `docs/dev-acceptance-matrix.md`
still freeze DEV at `http://74.48.78.17:6667`.
still freeze DEV at `http://74.48.78.17:16667`.
3. Every accepted artifact has `serviceId`, `commitId`, `image`, `tag`,
`digest` or `not_applicable` reason, `buildSource`, `deployEnv`, and
`healthTimestamp`.
+6 -6
View File
@@ -12,8 +12,8 @@ heavyweight e2e run by itself.
- Repository: `pikasTech/HWLAB`.
- MVP environment: `dev`.
- DEV endpoint: `http://74.48.78.17:6667`.
- PROD endpoint `:6666` is reserved and is not an MVP acceptance target.
- DEV endpoint: `http://74.48.78.17:16667`.
- Legacy endpoint `:6666` is deprecated and is not an MVP acceptance target; the browser entry is `:16666`.
- Runtime route: client, master `hwlab-edge-proxy`, `frp`, D601
`hwlab-dev/hwlab-router`, then HWLAB cloud/runtime services.
- HWLAB runtime services must keep the frozen service IDs in `README.md`.
@@ -89,7 +89,7 @@ Current unblock order:
approved kubeconfig/maintenance bridge, without reading Secrets.
4. Prove DEV `hwlab-cloud-api` DB env and health readiness with redacted values
only.
5. Repair the `:6667`/`frp`/edge/router path and rerun read-only DEV edge
5. Repair the `:16667`/`frp`/edge/router path and rerun read-only DEV edge
health before any M3, M4, or M5 live loop.
## Phase Gates
@@ -102,7 +102,7 @@ reason.
| --- | --- | --- | --- |
| Source-only | M0 contract, M2/M4/M5 source readiness | Worktree is based on latest `origin/main`; no secret or deployment access is needed; target files are docs, protocol, schema, fixtures, scripts, or manifests only. | Contract files parse; frozen endpoint and service IDs are unchanged; `npm run check` or the narrow validation command passes; no DEV/PROD mutation occurred. |
| Local smoke | M1 plus local M3/M4 contract smoke | Source-only has passed; commands use localhost or fixture data only; ports are ephemeral; no DEV endpoint call is needed. | Smoke commands pass; generated output states local or dry-run boundary; no real hardware, tunnel, kube, or deploy action occurred. |
| Dry-run | M2/M4/M5 readiness without runtime mutation | Source-only and local smoke pass; CLI/runtime fixtures identify `dev` and `http://74.48.78.17:6667`; operator confirms command includes `--dry-run` where applicable. | Dry-run output names MVP route, hardware trusted closed loop, agent automation closed loop, evidence records, and cleanup plan; output states no DEV/PROD changes were made. |
| Dry-run | M2/M4/M5 readiness without runtime mutation | Source-only and local smoke pass; CLI/runtime fixtures identify `dev` and `http://74.48.78.17:16667`; operator confirms command includes `--dry-run` where applicable. | Dry-run output names MVP route, hardware trusted closed loop, agent automation closed loop, evidence records, and cleanup plan; output states no DEV/PROD changes were made. |
| DEV runtime smoke | M2 DEV runtime observation | M0-M1 and required dry-runs pass; commander explicitly authorizes a read-only DEV smoke window; expected HWLAB artifacts and rollback owner are known; no secret reads are required. | Read-only health/status observations match `docs/dev-acceptance-matrix.md`; every observed service is HWLAB, in `dev`, and traceable to commit/image/tag/digest or a documented `not_applicable` reason. |
| MVP e2e | M3/M4/M5 DEV-only MVP acceptance | DEV runtime smoke has passed; commander explicitly authorizes a narrow DEV-only MVP smoke; project/gateway/agent/hardware scope is named; cleanup owner and stop criteria are recorded. | One bounded DEV-only flow completes: project, gateway session, resources, patch-panel wiring, agent and worker sessions, hardware operation, trace events, audit events, evidence record, and cleanup. No PROD or heavyweight e2e action occurred. |
@@ -169,7 +169,7 @@ Entry:
Exit:
- Frozen DEV endpoint remains `http://74.48.78.17:6667`.
- Frozen DEV endpoint remains `http://74.48.78.17:16667`.
- PROD is not introduced as an acceptance target.
- Frozen service IDs remain HWLAB service IDs.
- JSON, schema, script syntax, and documented contract checks pass.
@@ -184,7 +184,7 @@ Entry:
- Source-only gate passed.
- Commands are known local checks such as `npm run m1:smoke`,
`node scripts/m3-hardware-loop-smoke.mjs`, or targeted `node --test`.
- No command calls `http://74.48.78.17:6667`, `:6666`, kube, `frp`, edge
- No command calls `http://74.48.78.17:16667`, `:16666`, kube, `frp`, edge
runtime, or real hardware.
Exit:
+1 -1
View File
@@ -13,7 +13,7 @@ UniDesk or HWLAB runtime process.
- HWLAB runtime service identity is the frozen `hwlab-*` service ID set.
- DEV is the only accepted runtime environment for this guard.
- The fixed DEV endpoint is `http://74.48.78.17:6667`.
- The fixed DEV endpoint is `http://74.48.78.17:16667`.
- The DEV namespace is `hwlab-dev`.
- PROD deployment and PROD acceptance remain disabled.
- UniDesk backend, provider-gateway, and microservice proxy are forbidden
+2 -2
View File
@@ -317,13 +317,13 @@ export function createSkillsManifest({
commitId,
version,
namespace: "hwlab",
endpoint: "http://74.48.78.17:6667",
endpoint: "http://74.48.78.17:16667",
profiles: {
dev: {
name: "dev",
enabled: true,
namespace: "hwlab-dev",
endpoint: "http://74.48.78.17:6667",
endpoint: "http://74.48.78.17:16667",
notes: "explicit repo-local skills artifact"
}
},
+1 -1
View File
@@ -1,7 +1,7 @@
import fs from "node:fs";
import path from "node:path";
export const DEV_ENDPOINT = "http://74.48.78.17:6667";
export const DEV_ENDPOINT = "http://74.48.78.17:16667";
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";
+1 -1
View File
@@ -1,5 +1,5 @@
export const ENVIRONMENT_DEV = "dev";
export const DEV_ENDPOINT = "http://74.48.78.17:6667";
export const DEV_ENDPOINT = "http://74.48.78.17:16667";
export const JSON_RPC_VERSION = "2.0";
export const SERVICE_IDS = Object.freeze([
+2 -2
View File
@@ -9,7 +9,7 @@ import { fileURLToPath } from "node:url";
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:6667";
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";
@@ -171,7 +171,7 @@ function buildReport(fixture, evidence, result) {
devPreconditions: {
status: statusForResult(result),
requirements: [
"DEV route remains frozen at http://74.48.78.17:6667",
"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"
],
+1 -1
View File
@@ -28,7 +28,7 @@ async function captureCli(args) {
}
const summary = loadMvpGateSummary(repoRoot);
assert.equal(summary.endpoint, "http://74.48.78.17:6667");
assert.equal(summary.endpoint, "http://74.48.78.17:16667");
assert.deepEqual(
summary.milestones.map((item) => item.id),
["M0", "M1", "M2", "M3", "M4", "M5"]
+1 -1
View File
@@ -149,7 +149,7 @@ function expectSkillsManifest(manifest, fixture) {
assert.equal(manifest.commitId, fixture.skillCommitId);
assert.equal(manifest.version, fixture.skillVersion);
assert.equal(manifest.namespace, "hwlab");
assert.equal(manifest.endpoint, "http://74.48.78.17:6667");
assert.equal(manifest.endpoint, "http://74.48.78.17:16667");
assert.equal(manifest.profiles.dev.enabled, true);
assert.equal(manifest.profiles.dev.namespace, "hwlab-dev");
assert.equal(manifest.services[0].serviceId, AGENT_SKILLS_SERVICE_ID);
+2 -2
View File
@@ -12,7 +12,7 @@ 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:6667";
const DEV_ENDPOINT = "http://74.48.78.17:16667";
const ENVIRONMENT_DEV = "dev";
const JSON_RPC_VERSION = "2.0";
let serviceIds = [];
@@ -80,7 +80,7 @@ function assertArrayIncludesAll(label, actual, expected) {
function assertNoProdTarget(value, trail = "plan") {
if (typeof value === "string") {
assert.equal(value.includes(":6666"), false, `${trail} must not target PROD port`);
assert.equal(value.includes(":6666"), false, `${trail} must not target deprecated legacy port`);
assert.equal(/\bprod\b/i.test(value), false, `${trail} must not target PROD`);
return;
}
+1 -1
View File
@@ -289,7 +289,7 @@ function refreshDocuments({ deploy, catalog, workloads, target, publishRecords,
const service = catalogByService.get(serviceId);
if (!service) continue;
container.image = service.image;
updateEnvList(container.env, service, target, publishRecords?.get(serviceId) ?? null);
updateEnvList(container.env, service, target, records?.get(serviceId) ?? null);
}
}
+28 -18
View File
@@ -3,7 +3,7 @@ import { constants as fsConstants } from "node:fs";
import { access, readFile, writeFile } from "node:fs/promises";
import { request as httpRequest } from "node:http";
import path from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { fileURLToPath } from "node:url";
import { spawn } from "node:child_process";
import {
@@ -470,30 +470,40 @@ async function checkCloudApiDb(deploy, workloads, blockers) {
);
}
let health = null;
try {
const modulePath = pathToFileURL(path.join(repoRoot, "internal/cloud/server.mjs")).href;
const { buildHealthPayload } = await import(modulePath);
health = buildHealthPayload();
if (health.db?.ready !== true) {
addBlocker(
blockers,
"runtime_blocker",
"cloud-api-db",
`cloud-api health reports DB config blocked; missing ${health.db?.missingEnv?.join(", ") ?? "unknown DB env"}`
);
const configReady = missingManifest.length === 0 && missingK8s.length === 0 && missingSecretRefs.length === 0;
const health = {
status: configReady ? "degraded" : "blocked",
ready: false,
configReady,
connected: false,
connectionChecked: false,
fields: requiredEnv.map((env) => ({
name: env.name,
present: env.manifestPresent && env.k8sPresent && (!env.secretRef || env.secretRef.present),
redacted: env.redacted
})),
missingEnv: uniqueStrings([...missingManifest, ...missingK8s]),
secretRefs: requiredEnv
.filter((env) => env.secretRef)
.map((env) => ({
env: env.name,
secretName: env.secretRef.secretName,
secretKey: env.secretRef.secretKey,
present: env.secretRef.present,
redacted: true
})),
safety: {
liveDbEvidence: false
}
} catch (error) {
addBlocker(blockers, "observability_blocker", "cloud-api-health", `Cannot inspect cloud-api health payload: ${error.message}`);
}
};
return {
status: missingManifest.length === 0 && missingK8s.length === 0 && missingSecretRefs.length === 0 ? "contract-ready" : "contract-blocked",
status: configReady ? "contract-ready" : "contract-blocked",
requiredEnv,
missingManifest,
missingK8s,
missingSecretRefs,
runtimeHealth: health?.db ? summarizeDbContract(health.db) : null,
runtimeHealth: summarizeDbContract(health),
secretMaterialRead: false,
valuesRedacted: true,
liveDbEvidence: false,
+28 -23
View File
@@ -11,9 +11,9 @@ import { DEV_ENDPOINT, ENVIRONMENT_DEV } from "../../internal/protocol/index.mjs
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
const defaultReportPath = path.join(repoRoot, "reports/dev-gate/dev-edge-health.json");
const publicHost = "74.48.78.17";
const publicPort = 6667;
const publicPort = 16667;
const namespace = "hwlab-dev";
const tcpPorts = [6667, 7000, 7402];
const tcpPorts = [16667, 7000, 7402];
const runtimeServices = [
{ serviceId: "hwlab-cloud-api", port: 6667 },
{ serviceId: "hwlab-router", port: 7401 },
@@ -161,7 +161,7 @@ async function createDevGateReport(edgeHealth) {
devPreconditions: {
status,
requirements: [
"http://74.48.78.17:6667/health returns HWLAB DEV JSON with service, commit, and image evidence",
"http://74.48.78.17:16667/health returns HWLAB DEV JSON with service, commit, and image evidence",
"frps control on 74.48.78.17:7000 accepts the D601 frp client",
"hwlab-dev hwlab-edge-proxy, hwlab-tunnel-client, hwlab-router, and hwlab-cloud-api are observable",
"No PROD endpoint, secret read, restart, or UniDesk runtime substitute is used"
@@ -212,7 +212,7 @@ async function inspectContracts() {
const frps = await readText("deploy/frp/frps.dev.toml");
const deploy = await readJson("deploy/deploy.json");
const master = await readJson("deploy/master-edge/health-contract.json");
const frpsUsesVhost6667 = /vhostHTTPPort\s*=\s*6667/u.test(frps);
const frpsUsesVhostEdgePort = /vhostHTTPPort\s*=\s*(16667|6667)/u.test(frps);
return {
devEndpoint: DEV_ENDPOINT,
@@ -220,10 +220,15 @@ async function inspectContracts() {
frpcTargetsEdgeProxy:
/localIP\s*=\s*"hwlab-edge-proxy\.hwlab-dev\.svc\.cluster\.local"/u.test(frpc) &&
/localPort\s*=\s*6667/u.test(frpc) &&
/remotePort\s*=\s*6667/u.test(frpc),
frpsTcpRemotePort6667: /start\s*=\s*6667[\s\S]*end\s*=\s*6667/u.test(frps),
frpsUsesVhost6667,
configRisk: frpsUsesVhost6667 ? "port_conflict" : "none"
/remotePort\s*=\s*16667/u.test(frpc),
frpcTargetsCloudWeb:
/localIP\s*=\s*"hwlab-cloud-web\.hwlab-dev\.svc\.cluster\.local"/u.test(frpc) &&
/localPort\s*=\s*8080/u.test(frpc) &&
/remotePort\s*=\s*16666/u.test(frpc),
frpsTcpRemotePort16667: /start\s*=\s*16667[\s\S]*end\s*=\s*16667/u.test(frps),
frpsTcpRemotePort16666: /start\s*=\s*16666[\s\S]*end\s*=\s*16666/u.test(frps),
frpsUsesVhostEdgePort,
configRisk: frpsUsesVhostEdgePort ? "port_conflict" : "none"
},
masterEdge: {
endpoint: master.endpoint,
@@ -375,7 +380,7 @@ async function inspectClusterDns() {
}
function classify(report) {
const port6667 = report.publicTcp.find((probe) => probe.port === publicPort);
const publicEdgePort = report.publicTcp.find((probe) => probe.port === publicPort);
const frpsControl = report.publicTcp.find((probe) => probe.port === 7000);
const tunnelHealth = report.publicTcp.find((probe) => probe.port === 7402);
const publicHealth = report.publicHttp.find((probe) => probe.url.endsWith("/health"));
@@ -383,11 +388,11 @@ function classify(report) {
if (publicHealth?.ok && publicHealth.json?.serviceId && publicHealth.json?.environment === ENVIRONMENT_DEV) {
return classifyReachableHealth(publicHealth.json);
}
if (port6667?.status === "error" && port6667.code === "ECONNREFUSED") {
return classifyRefusedPort(port6667, frpsControl, tunnelHealth);
if (publicEdgePort?.status === "error" && publicEdgePort.code === "ECONNREFUSED") {
return classifyRefusedPort(publicEdgePort, frpsControl, tunnelHealth);
}
if (port6667?.status === "timeout") {
return blocker("dns_port_firewall_blocker", "public 6667 timed out before any HTTP response");
if (publicEdgePort?.status === "timeout") {
return blocker("dns_port_firewall_blocker", "public 16667 timed out before any HTTP response");
}
if (publicHealth && !publicHealth.ok && publicHealth.status) {
return blocker("app_health_blocker", `public /health returned HTTP ${publicHealth.status}`);
@@ -409,17 +414,17 @@ function classifyReachableHealth(json) {
return { status: "pass", classification: "none", blocker: null };
}
function classifyRefusedPort(port6667, frpsControl, tunnelHealth) {
function classifyRefusedPort(publicEdgePort, frpsControl, tunnelHealth) {
if (frpsControl?.status === "error" && frpsControl.code === "ECONNREFUSED") {
const allPortsRefused = tunnelHealth?.status === "error" && tunnelHealth.code === "ECONNREFUSED";
const diagnosis = {
likelyLayer: "master-edge/frps",
confidence: "high",
likelyCause: allPortsRefused
? "public 6667, frps control 7000, and tunnel health 7402 all refuse TCP connections; the master-edge frps listener or its ports are most likely down or closed"
: "public 6667 and frps control 7000 both refuse TCP connections; the master-edge frps listener or its ports are most likely down or closed",
? "public 16667, frps control 7000, and tunnel health 7402 all refuse TCP connections; the master-edge frps listener or its ports are most likely down or closed"
: "public 16667 and frps control 7000 both refuse TCP connections; the master-edge frps listener or its ports are most likely down or closed",
evidence: [
summarizeTcpProbe(port6667),
summarizeTcpProbe(publicEdgePort),
summarizeTcpProbe(frpsControl),
summarizeTcpProbe(tunnelHealth)
],
@@ -433,12 +438,12 @@ function classifyRefusedPort(port6667, frpsControl, tunnelHealth) {
return blocker("frp_blocker", diagnosis.likelyCause, diagnosis);
}
if (tunnelHealth?.status === "error" && tunnelHealth.code === "ECONNREFUSED") {
return blocker("frp_blocker", "public 6667 refuses TCP and tunnel health 7402 is not reachable", {
return blocker("frp_blocker", "public 16667 refuses TCP and tunnel health 7402 is not reachable", {
likelyLayer: "d601/frpc",
confidence: "medium",
likelyCause: "public 6667 and tunnel health 7402 both refuse TCP connections; the D601 frp client or its remote port is the likely break",
likelyCause: "public 16667 and tunnel health 7402 both refuse TCP connections; the D601 frp client or its remote port is the likely break",
evidence: [
summarizeTcpProbe(port6667),
summarizeTcpProbe(publicEdgePort),
summarizeTcpProbe(tunnelHealth)
],
notProven: [
@@ -448,12 +453,12 @@ function classifyRefusedPort(port6667, frpsControl, tunnelHealth) {
nextTask: "Restore the D601 tunnel client or its remote port, then rerun the read-only edge smoke."
});
}
return blocker("edge_proxy_blocker", "public 6667 refuses TCP connections", {
return blocker("edge_proxy_blocker", "public 16667 refuses TCP connections", {
likelyLayer: "master-edge/edge-proxy",
confidence: "medium",
likelyCause: "public 6667 refuses TCP while frps control 7000 stays reachable, so the public edge proxy or its listener is the likely break",
likelyCause: "public 16667 refuses TCP while frps control 7000 stays reachable, so the public edge proxy or its listener is the likely break",
evidence: [
summarizeTcpProbe(port6667),
summarizeTcpProbe(publicEdgePort),
summarizeTcpProbe(frpsControl)
],
notProven: [
@@ -245,7 +245,7 @@ function applyPriority(blocker) {
priority: "P2",
unblockOrder: 6,
unblocks: [issue(36), issue(38), issue(37), issue(39)],
rationale: "The :6667/frp path must be reachable before any DEV-LIVE M3, M4, or M5 evidence can be collected."
rationale: "The :16667/frp path must be reachable before any DEV-LIVE M3, M4, or M5 evidence can be collected."
};
}
@@ -606,7 +606,7 @@ function buildDoD(reports, milestones, blockers) {
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:6667."
summary: "No committed report proves live HTTP 200/JSON on http://74.48.78.17:16667."
},
{
id: "cloud-api-db-ready",
@@ -673,7 +673,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 :6667/frp/edge/router with HWLAB service identity and artifact identity.";
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.";
return "A committed report with the exact evidence level and command used.";
}
+6 -4
View File
@@ -351,9 +351,11 @@ function assertFrpStatic(frpc, frps, masterEdge) {
assert.equal(frpc.serverAddr, "74.48.78.17");
assert.equal(frpc.serverPort, 7000);
assert.equal(frps.bindPort, 7000);
assert.equal(Object.hasOwn(frps, "vhostHTTPPort"), false, "frps must not bind vhostHTTPPort because 6667 is reserved for the TCP proxy");
assert.ok(frpc.proxies.some((proxy) => proxy.name === "hwlab-dev-edge-proxy" && proxy.remotePort === 6667));
assert.ok(frps.allowPorts.some((port) => port.start === 6667 && port.end === 6667));
assert.equal(Object.hasOwn(frps, "vhostHTTPPort"), false, "frps must not bind vhostHTTPPort because 16667 is reserved for the TCP proxy");
assert.ok(frpc.proxies.some((proxy) => proxy.name === "hwlab-dev-edge-proxy" && proxy.remotePort === 16667));
assert.ok(frpc.proxies.some((proxy) => proxy.name === "hwlab-dev-cloud-web" && proxy.remotePort === 16666));
assert.ok(frps.allowPorts.some((port) => port.start === 16667 && port.end === 16667));
assert.ok(frps.allowPorts.some((port) => port.start === 16666 && port.end === 16666));
assert.equal(masterEdge.environment, ENVIRONMENT_DEV);
assert.equal(masterEdge.endpoint, DEV_ENDPOINT);
assert.equal(masterEdge.reverseLink.mode, "frp");
@@ -731,7 +733,7 @@ async function validateEdgeContracts(reporter, masterEdge) {
parseToml("deploy/frp/frps.dev.toml")
]);
assertFrpStatic(frpc, frps, masterEdge);
reporter.check("frp-master-edge-static", "edge", "pass", "FRP and master-edge contracts describe D601-to-master DEV on port 6667.");
reporter.check("frp-master-edge-static", "edge", "pass", "FRP and master-edge contracts describe D601-to-master DEV on public ports 16666/16667.");
} catch (error) {
reporter.check("frp-master-edge-static", "edge", "blocked", error.message);
reporter.block({
+1 -1
View File
@@ -66,7 +66,7 @@ function assertCommonSchema(commonSchema) {
function assertDeploySchema(deploySchema) {
const serviceIds = deploySchema.$defs.service.properties.serviceId.enum;
assert.deepEqual(serviceIds, SERVICE_IDS, "deploy service ids must match runtime constants");
assert.equal(deploySchema.properties.endpoint.const, "http://74.48.78.17:6667");
assert.equal(deploySchema.properties.endpoint.const, "http://74.48.78.17:16667");
}
function assertEnvelopeValidation() {
+4 -4
View File
@@ -592,7 +592,7 @@ function assertDevDeployApplyReport(report, label) {
assertObject(plan.target, `${label}.devDeployApply.target`);
assert.equal(plan.target.environment, "dev", `${label}.devDeployApply.target.environment`);
assert.equal(plan.target.namespace, "hwlab-dev", `${label}.devDeployApply.target.namespace`);
assert.equal(plan.target.endpoint, "http://74.48.78.17:6667", `${label}.devDeployApply.target.endpoint`);
assert.equal(plan.target.endpoint, "http://74.48.78.17:16667", `${label}.devDeployApply.target.endpoint`);
assert.equal(plan.target.prodDisabled, true, `${label}.devDeployApply.target.prodDisabled`);
assertObject(plan.artifactPlan, `${label}.devDeployApply.artifactPlan`);
@@ -817,7 +817,7 @@ async function validateDevEdgeReport(report, label) {
assertObject(report.edgeHealth, `${label}.edgeHealth`);
assertTimestamp(report.edgeHealth.generatedAt, `${label}.edgeHealth.generatedAt`);
assert.equal(report.edgeHealth.endpoint, "http://74.48.78.17:6667", `${label}.edgeHealth.endpoint`);
assert.equal(report.edgeHealth.endpoint, "http://74.48.78.17:16667", `${label}.edgeHealth.endpoint`);
assert.ok(
["pass", "blocker", "not_run"].includes(report.edgeHealth.status),
`${label}.edgeHealth.status must be pass, blocker, or not_run`
@@ -891,7 +891,7 @@ async function validateDevM3Report(report, label) {
}
assertObject(report.runtimeTarget, `${label}.runtimeTarget`);
assert.equal(report.runtimeTarget.endpoint, "http://74.48.78.17:6667", `${label}.runtimeTarget.endpoint`);
assert.equal(report.runtimeTarget.endpoint, "http://74.48.78.17:16667", `${label}.runtimeTarget.endpoint`);
assert.equal(report.runtimeTarget.namespace, "hwlab-dev", `${label}.runtimeTarget.namespace`);
assert.equal(report.runtimeTarget.environment, "dev", `${label}.runtimeTarget.environment`);
assert.equal(report.runtimeTarget.requiredBoxSimulators, 2, `${label}.runtimeTarget.requiredBoxSimulators`);
@@ -1153,7 +1153,7 @@ async function validateAggregatorV2Report(relativePath, report) {
assertTimestamp(report.generatedAt, `${label}.generatedAt`);
assert.match(report.generatedFromCommit, /^([a-f0-9]{7,40}|unknown)$/, `${label}.generatedFromCommit`);
assert.equal(report.environment, "dev", `${label}.environment`);
assert.equal(report.endpoint, "http://74.48.78.17:6667", `${label}.endpoint`);
assert.equal(report.endpoint, "http://74.48.78.17:16667", `${label}.endpoint`);
assert.equal(report.devOnly, true, `${label}.devOnly`);
assert.equal(report.prodDisabled, true, `${label}.prodDisabled`);
+1 -1
View File
@@ -244,7 +244,7 @@ function assertMasterHealthContract(contract, guard) {
"reverse link direction"
);
assert.equal(contract.reverseLink?.client, "hwlab-tunnel-client", "reverse link client");
assert.equal(contract.reverseLink?.publicPort, 6667, "reverse link public port");
assert.equal(contract.reverseLink?.publicPort, 16667, "reverse link public port");
assertForbiddenList(contract.forbiddenRuntimeSubstitutes, "master forbidden substitutes");
assertArray(contract.contracts, "master health contracts");
+14 -14
View File
@@ -18,7 +18,7 @@ export const gateSummary = {
"devOnly": true,
"prodDisabled": true,
"environment": "dev",
"endpoint": "http://74.48.78.17:6667",
"endpoint": "http://74.48.78.17:16667",
"namespace": "hwlab-dev",
"sourceSummary": "The DEV gate is anchored to the frozen matrix, gate contract, and M0-M5 milestone docs on origin/main.",
"localSmoke": {
@@ -44,7 +44,7 @@ export const gateSummary = {
"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] mode=dry-run endpoint=http://74.48.78.17:16667",
"[m2-smoke] no real DEV/PROD request was made",
"M3 hardware loop smoke passed",
"[m4-smoke] ok m4-agent-automation-loop-local-contract-smoke"
@@ -59,7 +59,7 @@ export const gateSummary = {
"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 health -> status: ok, environment: dev, endpoint: http://74.48.78.17:16667, 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"
],
@@ -68,17 +68,17 @@ export const gateSummary = {
"devPreconditions": {
"status": "blocked",
"requirements": [
"Obtain a live HTTP 200/JSON health observation from http://74.48.78.17:6667/health and /live",
"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",
"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"
"curl -fsS --max-time 5 http://74.48.78.17:16667/health",
"curl -fsS --max-time 5 http://74.48.78.17:16667/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"
"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"
],
"summary": "The frozen DEV endpoint is not reachable from this runner, so no live DEV gate can be claimed yet."
},
@@ -87,7 +87,7 @@ export const gateSummary = {
"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."
"summary": "http://74.48.78.17:16667/health and /live both fail with curl exit 7; live DEV ingress evidence is missing."
}
],
"milestones": [
@@ -296,7 +296,7 @@ export const gateSummary = {
"component": "DEV ingress",
"status": "healthy",
"deployEnv": "dev",
"endpoint": "http://74.48.78.17:6667/health",
"endpoint": "http://74.48.78.17:16667/health",
"observedBy": "fixture",
"dryRun": true,
"healthTimestamp": "2026-05-21T00:00:00.000Z"
@@ -307,7 +307,7 @@ export const gateSummary = {
"component": "master edge proxy",
"status": "healthy",
"deployEnv": "dev",
"endpoint": "http://74.48.78.17:6667",
"endpoint": "http://74.48.78.17:16667",
"observedBy": "fixture",
"dryRun": true,
"healthTimestamp": "2026-05-21T00:00:00.000Z"
@@ -351,7 +351,7 @@ export const gateSummary = {
"component": "Cloud Web",
"status": "healthy",
"deployEnv": "dev",
"endpoint": "http://74.48.78.17:6667",
"endpoint": "http://74.48.78.17:16667",
"observedBy": "fixture",
"dryRun": true,
"healthTimestamp": "2026-05-21T00:00:00.000Z"
@@ -439,7 +439,7 @@ export const gateSummary = {
"component": "CLI",
"status": "healthy",
"deployEnv": "dev",
"endpoint": "http://74.48.78.17:6667",
"endpoint": "http://74.48.78.17:16667",
"observedBy": "fixture",
"dryRun": true,
"healthTimestamp": "2026-05-21T00:00:00.000Z"
@@ -455,7 +455,7 @@ export const gateSummary = {
"gatewayId": "gtw_m5-dev-boundary",
"status": "connected",
"environment": "dev",
"endpoint": "http://74.48.78.17:6667/gateway"
"endpoint": "http://74.48.78.17:16667/gateway"
},
{
"gatewaySessionId": "gws_m5-simu-0001",
+1 -1
View File
@@ -1,6 +1,6 @@
export const runtime = {
endpoints: {
dev: "http://74.48.78.17:6667"
dev: "http://74.48.78.17:16667"
},
serviceRoute: [
"browser/CLI/gateway",