import fs from "node:fs"; import path from "node:path"; import { DEV_ENDPOINT } from "../protocol/index.mjs"; export { DEV_ENDPOINT }; export const DEFAULT_GATE_REPORT_SOURCE = "source:v02-live-api-summary"; export const V02_CLI_LIVE_CHECKS = Object.freeze([ "node scripts/run-bun.mjs tools/hwlab-cli/bin/hwlab-cli.ts client auth session --base-url http://74.48.78.17:19666 --no-session", "node scripts/run-bun.mjs tools/hwlab-cli/bin/hwlab-cli.ts client auth login --base-url http://74.48.78.17:19666 --username admin --password-env HWLAB_PASSWORD", "node scripts/run-bun.mjs tools/hwlab-cli/bin/hwlab-cli.ts client device-pods list --base-url http://74.48.78.17:19666", "node scripts/run-bun.mjs tools/hwlab-cli/bin/hwlab-cli.ts client device-pods status device-pod-71-freq --base-url http://74.48.78.17:19666", "node scripts/run-bun.mjs tools/hwlab-cli/bin/hwlab-cli.ts client workbench summary --base-url http://74.48.78.17:19666 --pod-id device-pod-71-freq" ]); export const M3_WORKBENCH_TOPOLOGY = Object.freeze({ projectId: "retired_legacy_mvp_fixture", projectStatus: "retired", gateways: Object.freeze([]), boxResources: Object.freeze([]), patchPanel: null }); function readJsonFile(repoRoot, relativePath) { const absolutePath = path.resolve(repoRoot, relativePath); return JSON.parse(fs.readFileSync(absolutePath, "utf8")); } function defaultMvpGateReport() { return { reportVersion: "v2", issue: "pikasTech/HWLAB#7", taskId: "v02-live-api-summary", acceptanceLevel: "v02_live_api_observation", devOnly: true, prodDisabled: true, gateStatus: "retired", sourceContract: { status: "pass", documents: [ "docs/reference/spec-v02-hwlab-cli.md", "docs/reference/spec-v02-services.md", "docs/reference/spec-device-pod.md", "docs/reference/g14-gitops-cicd.md" ], summary: "Legacy M5 fixture gate is retired. v0.2 validation uses short-connection hwlab-cli client commands against the same Cloud Web APIs used by the browser." }, validationCommands: V02_CLI_LIVE_CHECKS, localSmoke: { status: "pass", commands: ["node scripts/run-bun.mjs test tools/hwlab-cli/client.test.ts"], evidence: [ "hwlab-cli stores only cookie session metadata.", "device-pods and workbench commands use Cloud Web API paths, not fixtures." ], summary: "Short-connection CLI unit coverage replaces the old fixture dry-run gate." }, liveChecks: { status: "manual", commands: V02_CLI_LIVE_CHECKS, evidence: [ "Unauthenticated requests must return explicit auth state or HTTP auth errors with JSON output.", "Authenticated requests must exercise /auth, /v1/device-pods, /v1/live-builds, and health endpoints through 19666." ], summary: "Live non-visual workbench checks are performed through hwlab-cli client, not a service, image, Job, or CI gate." }, blockers: [ { type: "runtime_observation", scope: "v02-live-api", status: "manual", summary: "Run the current short-connection CLI against Cloud Web when live evidence is needed." } ], milestones: [ { id: "v0.2-cli", status: "active", commands: V02_CLI_LIVE_CHECKS, evidence: ["WEB-equivalent non-visual APIs are tested through hwlab-cli client."], summary: "The current validation path is short-connection live API probing." }, { id: "legacy-m5-fixture", status: "retired", commands: [], evidence: ["Old hwlab-cli artifact/test fixture is removed from active checks."], summary: "Do not restore the former M5 fixture gate or hwlab-cli image/job path." } ] }; } function clone(value) { return JSON.parse(JSON.stringify(value)); } function summarizeMilestone(milestone) { return { id: milestone.id, status: milestone.status, commandCount: milestone.commands?.length ?? 0, evidenceCount: milestone.evidence?.length ?? 0, summary: milestone.summary }; } function summarizeBlocker(blocker) { return { type: blocker.type, scope: blocker.scope, status: blocker.status, summary: blocker.summary }; } export function buildMvpGateSummary({ report = defaultMvpGateReport() } = {}) { const blockers = Array.isArray(report.blockers) ? report.blockers.map(summarizeBlocker) : []; const milestones = Array.isArray(report.milestones) ? report.milestones.map(summarizeMilestone) : []; return { generatedFrom: { gateReport: DEFAULT_GATE_REPORT_SOURCE, m5Plan: "retired" }, issue: report.issue ?? "pikasTech/HWLAB#7", supports: ["pikasTech/HWLAB#7"], gateStatus: report.gateStatus ?? "retired", activeGate: false, legacyFixtureGateRetired: true, acceptanceLevel: report.acceptanceLevel ?? "v02_live_api_observation", reportCommitId: report.commitId ?? "source-summary", dryRunOnly: false, devOnly: report.devOnly === true, prodDisabled: report.prodDisabled === true, environment: "v02", endpoint: "http://74.48.78.17:19666", namespace: "hwlab-v02", sourceSummary: report.sourceContract?.summary ?? "Legacy fixture gate retired.", localSmoke: report.localSmoke ?? null, liveChecks: report.liveChecks ?? null, blockers, milestones, topology: clone(M3_WORKBENCH_TOPOLOGY), serviceModel: { "hwlab-cli": { runtimeService: false, image: false, kubernetesJob: false, gitopsDesiredState: false, invocation: "short-connection client from G14:/root/hwlab-v02" } }, validationCommands: report.validationCommands ?? V02_CLI_LIVE_CHECKS, realDevGate: { sourcePlanCommand: "retired", command: "use hwlab-cli client live commands from docs/reference/spec-v02-hwlab-cli.md", requiresAllBlockersClear: false, requiresDryRunPass: false, requiresArtifactObservability: false, requiresD601RouteObservation: false, requiresHumanApprovalForRealDev: false }, safety: { mode: "short-connection-live-api", allowNetwork: true, allowDeploy: false, allowBrowserE2E: false, allowSecrets: false, prohibitedActions: ["create hwlab-cli image", "create hwlab-cli service", "create hwlab-cli job", "restore legacy M5 fixture gate"] } }; } export function loadMvpGateSummary(repoRoot, options = {}) { const reportPath = options.reportPath ?? null; const report = reportPath ? readJsonFile(repoRoot, reportPath) : defaultMvpGateReport(); const summary = buildMvpGateSummary({ report }); summary.generatedFrom = { gateReport: reportPath ?? DEFAULT_GATE_REPORT_SOURCE, m5Plan: "retired" }; return summary; }