557 lines
17 KiB
JSON
557 lines
17 KiB
JSON
{
|
|
"$schema": "https://hwlab.pikastech.local/fixtures/mvp/m5-e2e/dev-acceptance-checklist.schema.json",
|
|
"$id": "https://hwlab.pikastech.local/fixtures/mvp/m5-e2e/dev-acceptance-checklist.json",
|
|
"matrixVersion": "v1",
|
|
"issue": "pikasTech/HWLAB#22",
|
|
"environment": "dev",
|
|
"endpoint": "http://74.48.78.17:16667",
|
|
"publicEndpoints": {
|
|
"frontend": "http://74.48.78.17:16666",
|
|
"api": "http://74.48.78.17:16667",
|
|
"edge": "http://74.48.78.17:16667"
|
|
},
|
|
"internalServicePorts": [
|
|
{
|
|
"serviceId": "hwlab-cloud-api",
|
|
"scope": "k3s-service",
|
|
"port": 6667,
|
|
"note": "Internal k3s service port only; not a public DEV endpoint."
|
|
},
|
|
{
|
|
"serviceId": "hwlab-edge-proxy",
|
|
"scope": "k3s-service",
|
|
"port": 6667,
|
|
"note": "Internal k3s service/listen port only; public API/edge ingress is 16667."
|
|
}
|
|
],
|
|
"runtimeSubstitutePolicy": {
|
|
"allowedExternalRoles": [
|
|
"scheduling",
|
|
"ci",
|
|
"cd"
|
|
],
|
|
"forbiddenRuntimeSubstitutes": [
|
|
"unidesk-backend",
|
|
"unidesk-provider-gateway",
|
|
"unidesk-microservice-proxy"
|
|
]
|
|
},
|
|
"manualAcceptance": {
|
|
"referenceDoc": "docs/reference/m3-loop-rollout-runbook.md",
|
|
"m3MvpPassCondition": "res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1 with two distinct box simulators, two distinct gateway simulators, one patch-panel participant, and linked operation, trace, audit, and evidence IDs.",
|
|
"mustHaveEvidence": [
|
|
"two distinct box-simu identities",
|
|
"two distinct gateway-simu identities",
|
|
"patch-panel ownership of the route",
|
|
"operationId",
|
|
"traceId",
|
|
"auditId",
|
|
"evidenceId"
|
|
],
|
|
"supportOnlySignals": [
|
|
"SOURCE",
|
|
"LOCAL",
|
|
"DRY-RUN",
|
|
"fixture-only",
|
|
"edge-only",
|
|
"Cloud Web polish",
|
|
"generic console work",
|
|
"artifact report",
|
|
"desired-state plan"
|
|
],
|
|
"forbiddenM3PassSubstitutes": [
|
|
"box loopback",
|
|
"front-end direct state edit",
|
|
"UniDesk runtime substitution",
|
|
"UniDesk proxy substitution"
|
|
],
|
|
"failureClasses": [
|
|
"contract_blocker",
|
|
"environment_blocker",
|
|
"network_blocker",
|
|
"runtime_blocker",
|
|
"agent_blocker",
|
|
"observability_blocker",
|
|
"safety_blocker"
|
|
]
|
|
},
|
|
"m3EvidenceClassification": {
|
|
"p0Scope": "M3 virtual hardware trusted loop",
|
|
"requiredCardinality": {
|
|
"hwlab-box-simu": 2,
|
|
"hwlab-gateway-simu": 2,
|
|
"hwlab-patch-panel": 1
|
|
},
|
|
"m3Live": {
|
|
"requiredLink": "DO1 -> hwlab-patch-panel -> DI1",
|
|
"requiredIdentifiers": [
|
|
"operationId",
|
|
"traceId",
|
|
"auditId",
|
|
"evidenceId"
|
|
],
|
|
"classification": "DEV-LIVE"
|
|
},
|
|
"m3Support": [
|
|
"endpoint-freeze",
|
|
"read-only-edge-curl",
|
|
"source-contract",
|
|
"static-manifest-cardinality",
|
|
"local-smoke",
|
|
"dry-run-fixture"
|
|
],
|
|
"nonP0": [
|
|
"SOURCE",
|
|
"LOCAL",
|
|
"DRY-RUN",
|
|
"fixture-only",
|
|
"edge-only-diagnostic"
|
|
],
|
|
"promotionRule": "Do not classify M3 support or non-P0 evidence as DEV-LIVE unless the traced DO1 -> hwlab-patch-panel -> DI1 path is observed."
|
|
},
|
|
"artifactObservabilityFields": [
|
|
"serviceId",
|
|
"commitId",
|
|
"image",
|
|
"tag",
|
|
"digest",
|
|
"buildSource",
|
|
"deployEnv",
|
|
"healthTimestamp"
|
|
],
|
|
"artifactDigestPolicy": {
|
|
"requiredFor": [
|
|
"container-image",
|
|
"digestable-build-output"
|
|
],
|
|
"notApplicableValue": "not_applicable",
|
|
"reasonRequiredWhenNotApplicable": true
|
|
},
|
|
"route": [
|
|
{
|
|
"id": "dev-api-edge-endpoint",
|
|
"label": "DEV API/edge endpoint",
|
|
"serviceId": "hwlab-edge-proxy",
|
|
"endpoint": "http://74.48.78.17:16667",
|
|
"role": "public-api-edge-ingress"
|
|
},
|
|
{
|
|
"id": "dev-frontend-endpoint",
|
|
"label": "DEV frontend endpoint",
|
|
"serviceId": "hwlab-cloud-web",
|
|
"endpoint": "http://74.48.78.17:16666",
|
|
"role": "public-frontend"
|
|
},
|
|
{
|
|
"id": "master-edge-proxy",
|
|
"label": "master edge proxy",
|
|
"serviceId": "hwlab-edge-proxy",
|
|
"role": "edge-route"
|
|
},
|
|
{
|
|
"id": "frp",
|
|
"label": "frp",
|
|
"serviceId": "hwlab-tunnel-client",
|
|
"role": "tunnel"
|
|
},
|
|
{
|
|
"id": "d601-router",
|
|
"label": "D601 hwlab-dev/hwlab-router",
|
|
"serviceId": "hwlab-router",
|
|
"namespace": "hwlab-dev",
|
|
"role": "dev-router"
|
|
},
|
|
{
|
|
"id": "cloud-api-web",
|
|
"label": "cloud-api/web",
|
|
"serviceIds": [
|
|
"hwlab-cloud-api",
|
|
"hwlab-cloud-web"
|
|
],
|
|
"role": "cloud-surface"
|
|
}
|
|
],
|
|
"healthContracts": [
|
|
{
|
|
"component": "DEV ingress",
|
|
"serviceId": "hwlab-edge-proxy",
|
|
"probe": {
|
|
"method": "GET",
|
|
"url": "http://74.48.78.17:16667/health"
|
|
},
|
|
"requiredFields": [
|
|
"serviceId",
|
|
"deployEnv",
|
|
"healthTimestamp"
|
|
],
|
|
"success": "HTTP 2xx/3xx reaches the HWLAB DEV route and reports edge or downstream HWLAB identity.",
|
|
"failure": "Timeout, non-HWLAB response, PROD route, or missing artifact fields."
|
|
},
|
|
{
|
|
"component": "master edge proxy",
|
|
"serviceId": "hwlab-edge-proxy",
|
|
"probe": {
|
|
"type": "route-observation",
|
|
"target": "http://74.48.78.17:16667"
|
|
},
|
|
"requiredFields": [
|
|
"serviceId",
|
|
"commitId",
|
|
"image",
|
|
"tag",
|
|
"digest",
|
|
"buildSource",
|
|
"deployEnv",
|
|
"healthTimestamp"
|
|
],
|
|
"success": "DEV route forwards to frp and identifies its artifact.",
|
|
"failure": "No DEV route, wrong port, or missing route observability."
|
|
},
|
|
{
|
|
"component": "frp",
|
|
"serviceId": "hwlab-tunnel-client",
|
|
"probe": {
|
|
"type": "tunnel-status",
|
|
"target": "D601 hwlab-dev/hwlab-router"
|
|
},
|
|
"requiredFields": [
|
|
"serviceId",
|
|
"commitId",
|
|
"image",
|
|
"tag",
|
|
"digest",
|
|
"buildSource",
|
|
"deployEnv",
|
|
"healthTimestamp"
|
|
],
|
|
"success": "Tunnel is established from master edge to D601 router for DEV.",
|
|
"failure": "Tunnel down, wrong target, or ambiguous service identity."
|
|
},
|
|
{
|
|
"component": "D601 router",
|
|
"serviceId": "hwlab-router",
|
|
"namespace": "hwlab-dev",
|
|
"probe": {
|
|
"type": "router-health",
|
|
"target": "hwlab-dev/hwlab-router"
|
|
},
|
|
"requiredFields": [
|
|
"serviceId",
|
|
"commitId",
|
|
"image",
|
|
"tag",
|
|
"digest",
|
|
"buildSource",
|
|
"deployEnv",
|
|
"healthTimestamp"
|
|
],
|
|
"success": "Router is live in dev and forwards only to HWLAB DEV services.",
|
|
"failure": "Namespace mismatch, missing route, or stale health timestamp."
|
|
},
|
|
{
|
|
"component": "Cloud API",
|
|
"serviceId": "hwlab-cloud-api",
|
|
"probe": {
|
|
"methods": [
|
|
"GET /health",
|
|
"GET /live",
|
|
"POST /rpc"
|
|
]
|
|
},
|
|
"requiredFields": [
|
|
"serviceId",
|
|
"deployEnv",
|
|
"healthTimestamp"
|
|
],
|
|
"success": "Health is valid JSON with HWLAB cloud API identity and dev environment.",
|
|
"failure": "HTTP error, wrong service ID, wrong environment, or invalid JSON-RPC envelope."
|
|
},
|
|
{
|
|
"component": "Cloud Web",
|
|
"serviceId": "hwlab-cloud-web",
|
|
"probe": {
|
|
"commands": [
|
|
"npm run web:m3-readonly",
|
|
"npm run web:check",
|
|
"npm run web:build"
|
|
]
|
|
},
|
|
"requiredFields": [
|
|
"serviceId",
|
|
"commitId",
|
|
"buildSource",
|
|
"deployEnv",
|
|
"healthTimestamp"
|
|
],
|
|
"success": "Static assets exist, build succeeds, runtime uses public frontend :16666 and API/edge :16667, and Cloud Web exposes only read-only M3 diagnostics for topology, route, health, blockers, and evidence summary.",
|
|
"failure": "Endpoint drift, direct hardware write/control path, edge-only diagnostic promoted to M3 DEV-LIVE, or missing asset."
|
|
},
|
|
{
|
|
"component": "Agent manager",
|
|
"serviceId": "hwlab-agent-mgr",
|
|
"probe": {
|
|
"type": "agent-scheduler-health"
|
|
},
|
|
"requiredFields": [
|
|
"serviceId",
|
|
"commitId",
|
|
"image",
|
|
"tag",
|
|
"digest",
|
|
"buildSource",
|
|
"deployEnv",
|
|
"healthTimestamp"
|
|
],
|
|
"success": "Scheduler is live for dev and does not leave worker sessions open after smoke.",
|
|
"failure": "Scheduler unavailable, wrong environment, or unbounded worker session."
|
|
},
|
|
{
|
|
"component": "Agent worker",
|
|
"serviceId": "hwlab-agent-worker",
|
|
"probe": {
|
|
"type": "scoped-worker-health"
|
|
},
|
|
"requiredFields": [
|
|
"serviceId",
|
|
"commitId",
|
|
"image",
|
|
"tag",
|
|
"digest",
|
|
"buildSource",
|
|
"deployEnv",
|
|
"healthTimestamp"
|
|
],
|
|
"success": "Worker session is scoped to the DEV project and emits trace/audit identifiers.",
|
|
"failure": "Missing session identity, unsafe mutation, or cleanup failure."
|
|
},
|
|
{
|
|
"component": "Agent skills",
|
|
"serviceId": "hwlab-agent-skills",
|
|
"probe": {
|
|
"type": "skill-bundle-version"
|
|
},
|
|
"requiredFields": [
|
|
"serviceId",
|
|
"commitId",
|
|
"buildSource",
|
|
"deployEnv",
|
|
"healthTimestamp"
|
|
],
|
|
"success": "Skill artifact is traceable to commit/build source and compatible with worker.",
|
|
"failure": "Unversioned skill bundle or missing build source."
|
|
},
|
|
{
|
|
"component": "Gateway",
|
|
"serviceId": "hwlab-gateway",
|
|
"probe": {
|
|
"methods": [
|
|
"GET /health/live",
|
|
"GET /status"
|
|
]
|
|
},
|
|
"requiredFields": [
|
|
"serviceId",
|
|
"deployEnv",
|
|
"healthTimestamp"
|
|
],
|
|
"success": "Gateway boundary is live for dev and does not bypass patch-panel constraints.",
|
|
"failure": "Hardware boundary unavailable, non-dev gateway, or direct box mutation."
|
|
},
|
|
{
|
|
"component": "Gateway simulator",
|
|
"serviceId": "hwlab-gateway-simu",
|
|
"probe": {
|
|
"methods": [
|
|
"GET /health/live",
|
|
"GET /status",
|
|
"GET /boxes"
|
|
]
|
|
},
|
|
"requiredFields": [
|
|
"serviceId",
|
|
"deployEnv",
|
|
"healthTimestamp"
|
|
],
|
|
"success": "Simulator is live, lists expected box resources, and identifies the DEV project.",
|
|
"failure": "Simulator down, box list missing, or stale timestamp."
|
|
},
|
|
{
|
|
"component": "Box simulator",
|
|
"serviceId": "hwlab-box-simu",
|
|
"probe": {
|
|
"methods": [
|
|
"GET /health/live",
|
|
"GET /status"
|
|
]
|
|
},
|
|
"requiredFields": [
|
|
"serviceId",
|
|
"deployEnv",
|
|
"healthTimestamp"
|
|
],
|
|
"success": "Simulator is live and reports resources, ports, and patch-panel-only propagation.",
|
|
"failure": "Cross-device propagation outside patch panel or missing resource state."
|
|
},
|
|
{
|
|
"component": "Patch panel",
|
|
"serviceId": "hwlab-patch-panel",
|
|
"probe": {
|
|
"methods": [
|
|
"GET /health/live",
|
|
"GET /status",
|
|
"GET /wiring"
|
|
]
|
|
},
|
|
"requiredFields": [
|
|
"serviceId",
|
|
"deployEnv",
|
|
"healthTimestamp"
|
|
],
|
|
"success": "Wiring config is parseable and patch-panel state owns routing decisions.",
|
|
"failure": "Invalid topology, direct bypass path, or stale patch state."
|
|
},
|
|
{
|
|
"component": "CLI",
|
|
"serviceId": "hwlab-cli",
|
|
"probe": {
|
|
"commands": [
|
|
"npm run cli:health",
|
|
"npm run cli:dry-run"
|
|
]
|
|
},
|
|
"requiredFields": [
|
|
"serviceId",
|
|
"commitId",
|
|
"buildSource",
|
|
"deployEnv",
|
|
"healthTimestamp"
|
|
],
|
|
"success": "CLI uses the fixed DEV endpoint and dry-run states no DEV/PROD changes were made.",
|
|
"failure": "Wrong endpoint, missing dry-run guard, or real mutation attempted."
|
|
}
|
|
],
|
|
"smokeSteps": [
|
|
{
|
|
"id": "static-contract-parse",
|
|
"order": 1,
|
|
"probe": "Parse fixtures/mvp/m5-e2e/dev-acceptance-checklist.json and confirm docs/reference/MVP-e2e-acceptance.md exists.",
|
|
"successCriteria": "Checklist JSON parses and markdown file is present.",
|
|
"failureCriteria": "Missing file or invalid JSON.",
|
|
"blockerClass": "contract_blocker"
|
|
},
|
|
{
|
|
"id": "endpoint-freeze",
|
|
"order": 2,
|
|
"probe": "Compare documented and fixture DEV endpoints.",
|
|
"successCriteria": "Public frontend is exactly http://74.48.78.17:16666; public API/edge is exactly http://74.48.78.17:16667; internal 6667 appears only as a k3s service/listen port.",
|
|
"failureCriteria": "Any alternate public DEV endpoint, old public :6667, or PROD target.",
|
|
"blockerClass": "environment_blocker"
|
|
},
|
|
{
|
|
"id": "dev-ingress-health",
|
|
"order": 3,
|
|
"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"
|
|
},
|
|
{
|
|
"id": "edge-route",
|
|
"order": 4,
|
|
"probe": "Observe master edge proxy route table for DEV.",
|
|
"successCriteria": "Edge route maps DEV endpoint to frp and records artifact identity.",
|
|
"failureCriteria": "Missing route, stale route, or missing artifact identity.",
|
|
"blockerClass": "network_blocker"
|
|
},
|
|
{
|
|
"id": "frp-tunnel",
|
|
"order": 5,
|
|
"probe": "Observe frp tunnel status.",
|
|
"successCriteria": "Tunnel links master edge to D601 router for DEV.",
|
|
"failureCriteria": "Tunnel down or target mismatch.",
|
|
"blockerClass": "network_blocker"
|
|
},
|
|
{
|
|
"id": "d601-router",
|
|
"order": 6,
|
|
"probe": "Observe hwlab-dev/hwlab-router health/status.",
|
|
"successCriteria": "Router is live and forwards only to HWLAB DEV services.",
|
|
"failureCriteria": "Namespace mismatch or route bypass.",
|
|
"blockerClass": "runtime_blocker"
|
|
},
|
|
{
|
|
"id": "cloud-surface",
|
|
"order": 7,
|
|
"probe": "Check cloud API health and cloud web endpoint configuration.",
|
|
"successCriteria": "Cloud API health is valid on public :16667; web assets are served on public :16666 and point API traffic at :16667 or the internal k3s API service.",
|
|
"failureCriteria": "Bad health, endpoint drift, or direct hardware control from web.",
|
|
"blockerClass": "runtime_blocker"
|
|
},
|
|
{
|
|
"id": "gateway-sim-patch-panel",
|
|
"order": 8,
|
|
"probe": "Check gateway, gateway simulator, box simulator, and patch-panel health/status.",
|
|
"successCriteria": "Health/status JSON is parseable and topology keeps routing under patch-panel ownership; for M3 live, a traced DO1 -> patch-panel -> DI1 operation exists.",
|
|
"failureCriteria": "Missing health, invalid topology, bypass path, or any attempt to promote support/fixture evidence to M3 live.",
|
|
"blockerClass": "runtime_blocker"
|
|
},
|
|
{
|
|
"id": "agent-runtime",
|
|
"order": 9,
|
|
"probe": "Check agent manager, worker, and skills contracts.",
|
|
"successCriteria": "Agent artifacts are traceable; dry-run/scoped smoke emits session, trace, audit, and cleanup evidence.",
|
|
"failureCriteria": "Missing traceability, unsafe mutation, or cleanup leak.",
|
|
"blockerClass": "agent_blocker"
|
|
},
|
|
{
|
|
"id": "artifact-observability",
|
|
"order": 10,
|
|
"probe": "Verify required artifact observability fields for each accepted artifact.",
|
|
"successCriteria": "Every accepted artifact has service ID, commit, image/tag/digest or reason, build source, env, and health timestamp.",
|
|
"failureCriteria": "Missing required observability field.",
|
|
"blockerClass": "observability_blocker"
|
|
}
|
|
],
|
|
"blockerClasses": [
|
|
{
|
|
"id": "contract_blocker",
|
|
"description": "Static contract, schema, checklist, or documentation cannot be parsed or contradicts frozen names."
|
|
},
|
|
{
|
|
"id": "environment_blocker",
|
|
"description": "DEV endpoint, environment, namespace, or PROD boundary is wrong."
|
|
},
|
|
{
|
|
"id": "network_blocker",
|
|
"description": "Master edge, frp, D601 route, or public DEV ingress cannot be observed or routes incorrectly."
|
|
},
|
|
{
|
|
"id": "runtime_blocker",
|
|
"description": "HWLAB cloud, router, gateway, simulator, box simulator, or patch-panel runtime contract fails."
|
|
},
|
|
{
|
|
"id": "agent_blocker",
|
|
"description": "Agent manager, worker, skills, trace, audit, or cleanup contract fails."
|
|
},
|
|
{
|
|
"id": "observability_blocker",
|
|
"description": "Artifact identity, commit, image/tag/digest, build source, deploy env, or health timestamp is missing."
|
|
},
|
|
{
|
|
"id": "safety_blocker",
|
|
"description": "A prohibited action was attempted: real deployment, PROD target, heavyweight e2e, secret read, force push, or UniDesk runtime substitution."
|
|
}
|
|
],
|
|
"prohibitedActions": [
|
|
"real-dev-deploy",
|
|
"prod-deploy",
|
|
"prod-smoke",
|
|
"heavyweight-e2e",
|
|
"secret-or-token-read",
|
|
"force-push",
|
|
"unidesk-runtime-substitution"
|
|
],
|
|
"passRule": "All smoke steps must be successful or explicitly not applicable with a non-production reason, and every accepted artifact must satisfy the observability contract.",
|
|
"failRule": "Fail on any blocker class, wrong endpoint, wrong environment, missing HWLAB service identity, missing artifact observability, invalid JSON, or prohibited action."
|
|
}
|