diff --git a/cmd/hwlab-edge-proxy/main.mjs b/cmd/hwlab-edge-proxy/main.mjs index 4362d313..b0184274 100644 --- a/cmd/hwlab-edge-proxy/main.mjs +++ b/cmd/hwlab-edge-proxy/main.mjs @@ -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; } diff --git a/cmd/hwlab-tunnel-client/main.mjs b/cmd/hwlab-tunnel-client/main.mjs index 2608387d..24859993 100644 --- a/cmd/hwlab-tunnel-client/main.mjs +++ b/cmd/hwlab-tunnel-client/main.mjs @@ -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 }, diff --git a/deploy/README.md b/deploy/README.md index 9eb356aa..76975faa 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -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 ``` diff --git a/deploy/deploy.schema.json b/deploy/deploy.schema.json index fc171f40..f3255ba5 100644 --- a/deploy/deploy.schema.json +++ b/deploy/deploy.schema.json @@ -25,7 +25,7 @@ }, "endpoint": { "type": "string", - "const": "http://74.48.78.17:6667" + "const": "http://74.48.78.17:16667" }, "profiles": { "type": "object", diff --git a/deploy/frp/README.md b/deploy/frp/README.md index ea2088df..2a2e1350 100644 --- a/deploy/frp/README.md +++ b/deploy/frp/README.md @@ -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 diff --git a/deploy/frp/frpc.dev.toml b/deploy/frp/frpc.dev.toml index b8d1cd6e..fc56f75d 100644 --- a/deploy/frp/frpc.dev.toml +++ b/deploy/frp/frpc.dev.toml @@ -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" diff --git a/deploy/frp/frps.dev.toml b/deploy/frp/frps.dev.toml index 90390fbd..7607b065 100644 --- a/deploy/frp/frps.dev.toml +++ b/deploy/frp/frps.dev.toml @@ -1,8 +1,12 @@ bindPort = 7000 [[allowPorts]] -start = 6667 -end = 6667 +start = 16666 +end = 16666 + +[[allowPorts]] +start = 16667 +end = 16667 [[allowPorts]] start = 7402 diff --git a/deploy/k8s/dev/health-contract.yaml b/deploy/k8s/dev/health-contract.yaml index 72540900..17734c76 100644 --- a/deploy/k8s/dev/health-contract.yaml +++ b/deploy/k8s/dev/health-contract.yaml @@ -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", diff --git a/deploy/master-edge/README.md b/deploy/master-edge/README.md index 6d7d13f9..f03e7d84 100644 --- a/deploy/master-edge/README.md +++ b/deploy/master-edge/README.md @@ -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: diff --git a/deploy/master-edge/health-contract.json b/deploy/master-edge/health-contract.json index 12c273ef..1dc01e26 100644 --- a/deploy/master-edge/health-contract.json +++ b/deploy/master-edge/health-contract.json @@ -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": [ { diff --git a/docs/artifact-catalog.md b/docs/artifact-catalog.md index 4cc4cb30..3d8f4468 100644 --- a/docs/artifact-catalog.md +++ b/docs/artifact-catalog.md @@ -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. diff --git a/docs/dev-acceptance-checklist.json b/docs/dev-acceptance-checklist.json index 87fe5c85..0a74d6bf 100644 --- a/docs/dev-acceptance-checklist.json +++ b/docs/dev-acceptance-checklist.json @@ -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" diff --git a/docs/dev-acceptance-matrix.md b/docs/dev-acceptance-matrix.md index 353e8496..a22cc49c 100644 --- a/docs/dev-acceptance-matrix.md +++ b/docs/dev-acceptance-matrix.md @@ -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` | diff --git a/docs/dev-deploy-apply.md b/docs/dev-deploy-apply.md index d81354ff..bffda638 100644 --- a/docs/dev-deploy-apply.md +++ b/docs/dev-deploy-apply.md @@ -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 diff --git a/docs/dev-edge-health.md b/docs/dev-edge-health.md index 49fa621b..e3a2dbb4 100644 --- a/docs/dev-edge-health.md +++ b/docs/dev-edge-health.md @@ -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. diff --git a/docs/dev-evidence-blocker-aggregator.md b/docs/dev-evidence-blocker-aggregator.md index c425b437..dffaaaab 100644 --- a/docs/dev-evidence-blocker-aggregator.md +++ b/docs/dev-evidence-blocker-aggregator.md @@ -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 diff --git a/docs/dev-gate-preflight.md b/docs/dev-gate-preflight.md index 080a8b55..64b65ad5 100644 --- a/docs/dev-gate-preflight.md +++ b/docs/dev-gate-preflight.md @@ -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. diff --git a/docs/dev-m4-agent-loop.md b/docs/dev-m4-agent-loop.md index 08bf3744..1785bb69 100644 --- a/docs/dev-m4-agent-loop.md +++ b/docs/dev-m4-agent-loop.md @@ -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. diff --git a/docs/m0-contract-audit.md b/docs/m0-contract-audit.md index 858b4618..8b0ef4a1 100644 --- a/docs/m0-contract-audit.md +++ b/docs/m0-contract-audit.md @@ -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. diff --git a/docs/m1-local-smoke.md b/docs/m1-local-smoke.md index 8b34f2e3..ab8f6faa 100644 --- a/docs/m1-local-smoke.md +++ b/docs/m1-local-smoke.md @@ -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 diff --git a/docs/m2-dev-deploy-smoke.md b/docs/m2-dev-deploy-smoke.md index 5d935386..a465feea 100644 --- a/docs/m2-dev-deploy-smoke.md +++ b/docs/m2-dev-deploy-smoke.md @@ -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. diff --git a/docs/m3-hardware-loop.md b/docs/m3-hardware-loop.md index 18b6f944..51056fda 100644 --- a/docs/m3-hardware-loop.md +++ b/docs/m3-hardware-loop.md @@ -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. diff --git a/docs/m5-mvp-e2e.md b/docs/m5-mvp-e2e.md index 446277e3..23ffbe01 100644 --- a/docs/m5-mvp-e2e.md +++ b/docs/m5-mvp-e2e.md @@ -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`. diff --git a/docs/operator-runbook.md b/docs/operator-runbook.md index 3de4fb2b..86c05261 100644 --- a/docs/operator-runbook.md +++ b/docs/operator-runbook.md @@ -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: diff --git a/docs/runtime-boundary-guard.md b/docs/runtime-boundary-guard.md index e1f9ee1a..ada9aac8 100644 --- a/docs/runtime-boundary-guard.md +++ b/docs/runtime-boundary-guard.md @@ -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 diff --git a/internal/agent/index.mjs b/internal/agent/index.mjs index c96daf3e..9d75c1c5 100644 --- a/internal/agent/index.mjs +++ b/internal/agent/index.mjs @@ -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" } }, diff --git a/internal/mvp-gate/summary.mjs b/internal/mvp-gate/summary.mjs index 8e43c6e7..3ce06e17 100644 --- a/internal/mvp-gate/summary.mjs +++ b/internal/mvp-gate/summary.mjs @@ -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"; diff --git a/internal/protocol/index.mjs b/internal/protocol/index.mjs index 4ee09720..4b25cb64 100644 --- a/internal/protocol/index.mjs +++ b/internal/protocol/index.mjs @@ -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([ diff --git a/scripts/dev-m4-agent-loop-smoke.mjs b/scripts/dev-m4-agent-loop-smoke.mjs index 33041401..27160914 100644 --- a/scripts/dev-m4-agent-loop-smoke.mjs +++ b/scripts/dev-m4-agent-loop-smoke.mjs @@ -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" ], diff --git a/scripts/l6-cli-web-smoke.mjs b/scripts/l6-cli-web-smoke.mjs index afc5cc09..4f529967 100644 --- a/scripts/l6-cli-web-smoke.mjs +++ b/scripts/l6-cli-web-smoke.mjs @@ -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"] diff --git a/scripts/m4-agent-loop-smoke.mjs b/scripts/m4-agent-loop-smoke.mjs index ec1a2581..c5c88857 100644 --- a/scripts/m4-agent-loop-smoke.mjs +++ b/scripts/m4-agent-loop-smoke.mjs @@ -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); diff --git a/scripts/m5-mvp-e2e-dry-run.mjs b/scripts/m5-mvp-e2e-dry-run.mjs index 256df6e6..51d5405f 100644 --- a/scripts/m5-mvp-e2e-dry-run.mjs +++ b/scripts/m5-mvp-e2e-dry-run.mjs @@ -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; } diff --git a/scripts/refresh-artifact-catalog.mjs b/scripts/refresh-artifact-catalog.mjs index ae263a58..3d707ee1 100644 --- a/scripts/refresh-artifact-catalog.mjs +++ b/scripts/refresh-artifact-catalog.mjs @@ -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); } } diff --git a/scripts/src/dev-deploy-apply.mjs b/scripts/src/dev-deploy-apply.mjs index f3c0fa26..784592d4 100755 --- a/scripts/src/dev-deploy-apply.mjs +++ b/scripts/src/dev-deploy-apply.mjs @@ -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, diff --git a/scripts/src/dev-edge-health-smoke-lib.mjs b/scripts/src/dev-edge-health-smoke-lib.mjs index 9e903f65..6f2ee984 100644 --- a/scripts/src/dev-edge-health-smoke-lib.mjs +++ b/scripts/src/dev-edge-health-smoke-lib.mjs @@ -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: [ diff --git a/scripts/src/dev-evidence-blocker-aggregator.mjs b/scripts/src/dev-evidence-blocker-aggregator.mjs index 12780889..f9e4fd66 100644 --- a/scripts/src/dev-evidence-blocker-aggregator.mjs +++ b/scripts/src/dev-evidence-blocker-aggregator.mjs @@ -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."; } diff --git a/scripts/src/dev-gate-preflight.mjs b/scripts/src/dev-gate-preflight.mjs index 2359d639..15e15067 100644 --- a/scripts/src/dev-gate-preflight.mjs +++ b/scripts/src/dev-gate-preflight.mjs @@ -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({ diff --git a/scripts/validate-contract.mjs b/scripts/validate-contract.mjs index a5d6a2be..0d30c2b1 100644 --- a/scripts/validate-contract.mjs +++ b/scripts/validate-contract.mjs @@ -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() { diff --git a/scripts/validate-dev-gate-report.mjs b/scripts/validate-dev-gate-report.mjs index 36d2280d..4de283d9 100644 --- a/scripts/validate-dev-gate-report.mjs +++ b/scripts/validate-dev-gate-report.mjs @@ -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`); diff --git a/scripts/validate-runtime-boundary.mjs b/scripts/validate-runtime-boundary.mjs index f588cc1b..6ca9ff01 100644 --- a/scripts/validate-runtime-boundary.mjs +++ b/scripts/validate-runtime-boundary.mjs @@ -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"); diff --git a/web/hwlab-cloud-web/gate-summary.mjs b/web/hwlab-cloud-web/gate-summary.mjs index 1ba23880..a14cf236 100644 --- a/web/hwlab-cloud-web/gate-summary.mjs +++ b/web/hwlab-cloud-web/gate-summary.mjs @@ -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", diff --git a/web/hwlab-cloud-web/runtime.mjs b/web/hwlab-cloud-web/runtime.mjs index f56e840b..7b015c05 100644 --- a/web/hwlab-cloud-web/runtime.mjs +++ b/web/hwlab-cloud-web/runtime.mjs @@ -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",