docs: consolidate v0.2 documentation governance

This commit is contained in:
Codex
2026-05-28 21:16:43 +08:00
parent e7fa3d67d0
commit 44851d8eb3
51 changed files with 139 additions and 3327 deletions
+8 -1
View File
@@ -30,6 +30,12 @@ HWLAB 是硬件实验室运行面和控制面项目。本文是 agent、指挥
- 架构迁移时,过时的自检、预检、guard、gate 优先拆除;不要在旧门禁上继续加例外、加复杂度或制造噪声。
- 新增自检、预检、guard、gate 必须遵循最小原则,只覆盖明确高价值风险;禁止乱加门禁导致系统僵化、难迁移、难调试或产生大量误报和摩擦。
## P0 v0.2 文档治理
- `AGENTS.md` 是唯一顶级入口;`README.md``docs/*.md``docs/*.json``docs/plan/*.md` 不再作为 v0.2 仓库内文档形态保留。
- 计划、里程碑、阶段迁移、一次性排障和旧报告全文迁入 GitHub issue;长期参考只吸收稳定结论并引用对应 issue。
- v0.2 文档树收敛、D601/G14 旧口径处理和 JSON 放置边界见 [docs/reference/spec-v02-documentation-governance.md](docs/reference/spec-v02-documentation-governance.md)。
## 工作区
- G14 分支固定 source workspace 是 G14 节点上的 `/root/hwlab`,固定使用 `G14` 分支和 `origin git@github.com:pikasTech/HWLAB.git`。在 G14 上进行代码、文档、GitOps render、Tekton/poller/Argo CD 修复或 CI/CD 验证前,必须先确认 `pwd``/root/hwlab``git status --short --branch``G14...origin/G14`;不满足时先停止并修正 workspace。
@@ -78,6 +84,7 @@ HWLAB 是硬件实验室运行面和控制面项目。本文是 agent、指挥
- 中文优先规则:[docs/reference/chinese-first-documentation.md](docs/reference/chinese-first-documentation.md)
- 用户反馈分流规则:[docs/reference/user-feedback-triage.md](docs/reference/user-feedback-triage.md)
- 文档治理与 docs-spec 本地权威:[docs/reference/documentation-governance.md](docs/reference/documentation-governance.md)
- v0.2 文档治理规格、过程文档迁 issue、`docs/` 根目录清理和 D601/G14 旧口径收敛:[docs/reference/spec-v02-documentation-governance.md](docs/reference/spec-v02-documentation-governance.md)
- 架构和 M3 主线:[docs/reference/architecture.md](docs/reference/architecture.md)
- DEV 运行态、端口、k3s 和 DB DNS 边界:[docs/reference/dev-runtime-boundary.md](docs/reference/dev-runtime-boundary.md)
- G14 GitOps 发布、SecretRef preflight、runner/host 边界、镜像发布和单纯文档/CLI 直推规则:[docs/reference/g14-gitops-cicd.md](docs/reference/g14-gitops-cicd.md)、[docs/reference/commander-collaboration.md](docs/reference/commander-collaboration.md)
@@ -97,7 +104,7 @@ HWLAB 是硬件实验室运行面和控制面项目。本文是 agent、指挥
- 中文优先:issue、PR 正文、长期参考文档和用户可见说明默认用中文;英文术语只在命令、协议、接口、ID、路径和标准名需要保真时保留,详见 [docs/reference/chinese-first-documentation.md](docs/reference/chinese-first-documentation.md)。
- 用户反馈优先:用户和参谋提出的问题默认按高优先级用户反馈处理,blocker 状态不能替代反馈分流,必须挂到 [pikasTech/HWLAB#7](https://github.com/pikasTech/HWLAB/issues/7) 醒目位置,详见 [docs/reference/user-feedback-triage.md](docs/reference/user-feedback-triage.md)。
- docs-spec 本地权威优先:涉及 `AGENTS.md``docs/reference/*.md` 或过程文档蒸馏时,先按 [docs/reference/documentation-governance.md](docs/reference/documentation-governance.md) 执行,不另建同级规则副本。
- 交付路径按风险选择:单纯文档、CLI/helper 轻量变更直接提交并 push 到 `origin/G14`,不开 PR;业务代码、运行面、发布链路、Secret、权限、数据迁移、PROD 或其他高风险变更走 PR 工作流,详见 [docs/reference/commander-collaboration.md](docs/reference/commander-collaboration.md)。
- 交付路径按风险选择:单纯文档、CLI/helper 轻量变更直接提交并 push 到当前工作线的 source branchG14 默认 `origin/G14``v0.2` 默认 `origin/v0.2`;业务代码、运行面、发布链路、Secret、权限、数据迁移、PROD 或其他高风险变更走 PR 工作流,详见 [docs/reference/commander-collaboration.md](docs/reference/commander-collaboration.md)。
## 常用轻量命令
-102
View File
@@ -1,102 +0,0 @@
# HWLAB
HWLAB is the hardware lab runtime and control plane for MVP development.
This repository is intentionally small at L0. It defines the shared protocol
contract, schema skeletons, deploy manifest schema, and minimal validation
entry points that later service implementations must follow.
## MVP Freeze
- MVP scope is DEV only.
- DEV browser/frontend endpoint is fixed at `http://74.48.78.17:16666/`.
- DEV API/edge/live endpoint is fixed at `http://74.48.78.17:16667`.
- Legacy `:6666` and `:6667` are historical/deprecated only and are not MVP
acceptance targets.
- UniDesk may be used only as an external scheduling, CI, or CD base.
- HWLAB runtime services must not be replaced by UniDesk backend,
provider-gateway, or microservice proxy implementations.
## Frozen Service IDs
- `hwlab-cloud-api`
- `hwlab-cloud-web`
- `hwlab-agent-mgr`
- `hwlab-agent-worker`
- `hwlab-gateway`
- `hwlab-gateway-simu`
- `hwlab-box-simu`
- `hwlab-patch-panel`
- `hwlab-router`
- `hwlab-tunnel-client`
- `hwlab-edge-proxy`
- `hwlab-cli`
- `hwlab-agent-skills`
## Frozen Repository Layout
The MVP branches may add implementation files under these paths:
- `cmd/...`
- `internal/...`
- `web/hwlab-cloud-web`
- `tools/hwlab-cli`
- `skills`
- `protocol/schemas`
- `deploy/deploy.json`
- `deploy/k8s/base/dev/prod`
- `deploy/master-edge`
- `deploy/frp`
- `scripts/bootstrap-skills.sh`
- `scripts/worker-entrypoint.sh`
## Contract Index
- Protocol contract: [protocol/README.md](protocol/README.md)
- JSON-RPC envelope: [protocol/json-rpc.md](protocol/json-rpc.md)
- Error codes: [protocol/errors.md](protocol/errors.md)
- Audit fields: [protocol/audit.md](protocol/audit.md)
- Capability model: [protocol/capabilities.md](protocol/capabilities.md)
- Topology constraints: [protocol/topology.md](protocol/topology.md)
- MVP e2e contract: [protocol/mvp-e2e-contract.md](protocol/mvp-e2e-contract.md)
- JSON Schemas: [protocol/schemas](protocol/schemas)
- Deploy schema: [deploy/deploy.schema.json](deploy/deploy.schema.json)
- M3 rollout support runbook: [docs/reference/m3-loop-rollout-runbook.md](docs/reference/m3-loop-rollout-runbook.md)
## Validation
Run the lightweight validation suite:
```sh
npm run check
```
Run only the L2 gateway/box simulator runtime smoke:
```sh
npm run l2:smoke
```
## L6 Manual Acceptance Entry
The external MVP acceptance surface is DEV-only and report-driven:
```sh
npm run l6:smoke
npm run web:m3-readonly
npm run web:check
npm run cli:dry-run
node tools/hwlab-cli/bin/hwlab-cli.mjs test e2e --env dev --mvp
```
`npm run web:m3-readonly` is the Cloud Web #59 guardrail: it checks that the
browser entry remains on public `:16666`, API/edge diagnostics remain on public
`:16667`, the page only calls read-only diagnostics RPCs, and M3 stays blocked
unless the real `DO1 -> hwlab-patch-panel -> DI1` DEV-LIVE evidence exists.
The CLI command defaults to a JSON dry-run plan sourced from
`GitHub issue/PR comments` and
`fixtures/mvp/m5-e2e/dry-run-plan.json`. A live DEV attempt requires
`--live --confirm-dev --confirmed-non-production`; with open gate blockers it
returns `BLOCKED` evidence rather than using fixtures or UniDesk runtime as a
substitute.
-189
View File
@@ -1,189 +0,0 @@
# HWLAB Artifact Catalog Contract
The artifact catalog is the DEV-only MVP contract for interpreting generated
deployment artifacts. It pins which HWLAB service image, commit, profile,
namespace, and health path GitOps render must inject into runtime manifests.
`deploy/deploy.json` stays the human-authored runtime config truth source.
This file is not automatically a CI publish record. It proves only the state it
declares:
- `artifactState: "contract-skeleton"` means the source/artifact commit and image
tags are aligned, but `ciPublished=false`, `registryVerified=false`, and every
digest must stay `not_published`.
- `artifactState: "published"` is allowed only after a DEV publish report proves
every required enabled service was published for the same source commit with a
real `sha256:<64 hex>` registry digest. Services explicitly disabled in the
service inventory must stay `not_published` and carry a disabled reason.
Do not infer registry existence, digest values, or deployment from commit tags.
Real publish evidence must come from the publishing workflow and registry
metadata, then be copied into the catalog by the refresh command below.
## Scope
- Environment: DEV only.
- Namespace: `hwlab-dev`.
- Public DEV endpoint: `http://74.48.78.17:16667`.
- Profile: `dev`.
- Health path: `/health/live`.
- Artifact state: contract skeleton only.
- PROD deployment, PROD smoke, secret reads, force push, real image publish, and
UniDesk runtime substitution are forbidden.
## Files
| File | Role |
| --- | --- |
| `deploy/artifact-catalog.dev.json` | Machine-readable DEV artifact identity truth for generated image, digest, commit, and publish provenance fields. |
| `deploy/deploy.json` | Human-authored DEV runtime config such as service topology, env, health, profile, replicas, and endpoints. |
| `scripts/g14-gitops-render.mjs` | Declares the Tekton primitive CI tasks and minimal guardrails that generate the G14 CI/CD control plane. |
| `scripts/deploy-desired-state-plan.mjs` | Read-only planner/checker for catalog artifact identity, generated identity leakage into deploy config, and deploy/runtime config contracts. |
| `scripts/refresh-artifact-catalog.mjs` | Previews artifact catalog identity by default; only G14 Tekton promotion uses `--write` to update `deploy/artifact-catalog.dev.json` before committing generated state to `G14-gitops`. |
| `scripts/validate-artifact-catalog.mjs` | Local static validator for the catalog and deploy manifest skeleton. |
| `scripts/preflight-dev-base-image.mjs` | Local DEV builder base-image preflight for future artifact publish. |
| `docs/dev-base-image-preflight.md` | Operator contract for interpreting preflight readiness and blockers. |
## Pin Rules
Every service entry in `deploy/artifact-catalog.dev.json` must satisfy these
rules:
| Field | Rule |
| --- | --- |
| `serviceId` | Must be one of the frozen HWLAB service IDs and must appear exactly once. |
| `commitId` | Must match the top-level catalog commit ID. Short or full lowercase Git SHA is allowed. |
| `image` | Must match the DEV registry target `<registry>/<namespace>/<serviceId>:<imageTag>`. The matching field must not be copied into `deploy/deploy.json`. |
| `imageTag` | Must be the first seven characters of `commitId`. Mutable tags such as `latest`, `dev`, or `main` are forbidden. |
| `profile` | Must be `dev`. |
| `namespace` | Must be `hwlab-dev`. |
| `healthPath` | Must be `/health/live` and match the DEV health contract. |
| `publishState` | Must be `skeleton-only` in a blocked skeleton catalog, or `published` only when the catalog was refreshed from a successful publish report. |
| `sourceState` | Must be `source-present` for MVP services with repository source, or `intentionally-disabled` for zero-replica services excluded from MVP publication. |
| `artifactRequired` | Must match `serviceInventory.requiredServiceIds`; only required services need publish digests. |
| `artifactScope` | `required` for services that must be published, or `disabled` with a `notPublishedReason`. |
| `digest` | Must be `not_published` in the skeleton catalog; it may be a registry `sha256:<64 hex>` digest only after publish evidence exists. |
The catalog `commitId` is the artifact source commit, not proof that a registry
artifact exists. It must match every service `commitId` and the image tag. If a
later target ref changes artifact build inputs after the
publish source, the DEV gate preflight may reopen `artifact-source-commit` even
when the base-image blocker is already closed.
## Desired-State Plan
Use the read-only planner before refreshing or reviewing deploy desired-state:
```sh
node scripts/deploy-desired-state-plan.mjs --plan --pretty
node scripts/deploy-desired-state-plan.mjs --check
node scripts/deploy-desired-state-plan.mjs --target-ref origin/G14 --pretty
node scripts/deploy-desired-state-plan.mjs --target-tag <tag> --pretty
node scripts/deploy-desired-state-plan.mjs --promotion-commit <sha> --check
```
The planner treats `deploy/deploy.json` as human-authored runtime config,
`deploy/artifact-catalog.dev.json` as artifact identity truth, and
`deploy/k8s/base/workloads.yaml` as a runtime template. It reports catalog
service `commitId`/`image`/`imageTag`, blocks generated artifact identity that
leaks into `deploy.json`, and leaves workload image/env mirror values to GitOps
render because render overwrites them from the catalog.
`--check` exits non-zero when the source files are missing or invalid, generated
artifact identity leaks into `deploy.json`, an explicit target tag is invalid or
mutable, or catalog artifact identity does not match the requested target. The
source branch catalog is only a seed contract; published artifact identity is
stored on `G14-gitops`. The optional report snapshot is contextual evidence only
and is not an authoritative desired-state source.
For PR review or CI/CD promotion handoff, use `--promotion-commit <sha>
--check`. That mode is stricter than a `--target-ref` plan: the catalog
top-level commit and each catalog service commit/image tag must align with the
promotion commit/tag. A stale but internally consistent catalog is a blocker in
promotion mode because applying it would roll DEV back.
The planner does not prove registry existence, publish success, DEV apply, or
M3 DEV-LIVE. Only real DEV observation of
`res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1` with operation,
trace, audit, and evidence records can be called M3 DEV-LIVE.
## Refresh Boundary
Human source work must not refresh artifact identity into the source branch. To
preview what a blocked catalog would look like, use read-only mode:
```sh
node scripts/refresh-artifact-catalog.mjs --target-ref HEAD --blocked --no-write
node scripts/deploy-desired-state-plan.mjs --check
```
This prints the planned catalog state and does not modify any repository file.
Blocked skeleton refresh is intentionally preview-only.
After a successful DEV artifact publish, only the G14 Tekton promotion path may
record digests from the publish report:
```sh
node scripts/refresh-artifact-catalog.mjs --target-ref <source-sha> --publish-report /workspace/source/dev-artifacts.json --write
```
The publish-report mode refuses to update the catalog unless the report says
`artifactPublish.status="published"`, covers every frozen service in the v2
publish plan, matches the target source commit, and contains a valid `sha256`
digest for each required service. Disabled services remain `skeleton-only` with
`digest: "not_published"`. The written catalog is committed only to
`G14-gitops`; `deploy/deploy.json` remains human-authored source truth.
## Relationship To `deploy/deploy.json`
`deploy/deploy.json` remains the human-authored deploy manifest. The artifact
catalog does not replace it and must not be consumed as proof that a release was
built. GitOps render combines human config from `deploy.json` with generated
artifact identity from the catalog; artifact identity must not be copied back
into `deploy.json`.
If a future CI workflow publishes real images, it should update or generate a
publish result that includes registry digests and provenance. That publish
result may be compared with this contract, but it must not be inferred from this
contract.
## DEV Builder Preflight
Before a future DEV artifact publish attempts to build or publish service
images, run:
```sh
npm run --silent dev-base-image:preflight
```
The preflight is local-only and checks for an approved builder base image through
`HWLAB_DEV_BASE_IMAGE`, a local `node:20-*` Docker image, or an explicit local
HWLAB dev base tag such as `hwlab-dev-base:<tag>`. It prints the image source,
local tag, image ID, publish usability, blockers, next steps, and
machine-readable preload/provision commands. The recommended source is
`node:20-bookworm-slim`; the recommended HWLAB-local tag is
`127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim`. A blocked result
means artifact publish must stop and must not be reported as a successful
publish.
## Validation
Run the local static validator:
```sh
node --check scripts/deploy-desired-state-plan.mjs
node --check scripts/src/deploy-desired-state-plan.mjs
node --test scripts/deploy-desired-state-plan.test.mjs
node scripts/deploy-desired-state-plan.mjs --check
node --check scripts/validate-artifact-catalog.mjs
node --check scripts/refresh-artifact-catalog.mjs
node --check scripts/preflight-dev-base-image.mjs
node --check scripts/src/dev-base-image-preflight.mjs
node scripts/validate-artifact-catalog.mjs
```
The validator and refresh command read local repository files and optional
publish reports; refresh is read-only unless `--write` is explicitly supplied.
The desired-state planner has the same read-only boundary.
These commands do not contact a registry, read secrets, build images, push
images, deploy to DEV, or deploy to PROD.
-130
View File
@@ -1,130 +0,0 @@
# Cloud API Runtime
The L1 `hwlab-cloud-api` runtime is a minimal local HTTP/JSON-RPC service. It
does not deploy to DEV or PROD from source tests and does not claim live
database persistence unless both DB readiness and the durable runtime adapter
readiness are live.
## Local Smoke
Run:
```sh
node scripts/cloud-api-runtime-smoke.mjs
```
The smoke starts `cmd/hwlab-cloud-api` on `127.0.0.1` with an ephemeral port
and verifies:
- `GET /health` reports `status: "degraded"` when live DB persistence is not
connected.
- `GET /health` reports DB readiness and runtime durable adapter readiness as
separate components. A memory adapter remains non-durable even when DB env
fields are present.
- The DB contract reports required env names, redacted Secret refs, env
injection, connection attempt status, connection result, `liveConnected`,
`liveDbEvidence`, DNS/TCP/auth/schema readiness layers, and redaction/safety
fields without exposing DB URL or secret values.
- `gateway.session.register`, `box.resource.register`,
`box.capability.report`, `hardware.invoke.shell`, `audit.event.query`, and
`evidence.record.query` round-trip through the same runtime store.
- Shell invoke requests are accepted as recorded cloud operations but report
`dispatchStatus: "not_connected"` until a real gateway shell adapter exists.
- Audit and evidence records use the protocol schema field names.
## Persistence Boundary
The default local runtime store is process-local memory:
- `runtime.adapter: "memory"`
- `runtime.durable: false`
- `runtime.status: "degraded"`
This remains the safe local default. DEV can opt into the durable adapter with
non-secret env flags:
- `HWLAB_CLOUD_RUNTIME_ADAPTER=postgres`
- `HWLAB_CLOUD_RUNTIME_DURABLE=true`
The Postgres adapter uses `HWLAB_CLOUD_DB_URL` from
`hwlab-cloud-api-dev-db/database-url`; source records only the Secret reference
and non-secret DNS contract. `HWLAB_CLOUD_DB_SSL_MODE` is the runtime authority
for DB TLS mode; if it is `disable`, the adapter strips URL `sslmode` query
parameters before opening the Postgres pool so stale Secret URL parameters
cannot override the DEV SSL contract. The adapter reports `runtime.durable: true`
only after the configured adapter proves all durable gates through read-only
runtime checks:
- auth/query access to the configured DB path;
- required runtime table and column schema;
- the source-controlled migration ledger row for
`0001_cloud_core_skeleton` / `runtime-durable-postgres-v1`;
- read readiness against the runtime tables used by audit and evidence
queries.
If DB SSL negotiation, auth, schema, migration, or read readiness is missing, `/health/live`
stays degraded with `runtime.durable: false`, `runtime.durableRequested: true`,
and a runtime blocker such as `runtime_durable_adapter_ssl_blocked`,
`runtime_durable_adapter_auth_blocked`, `runtime_durable_adapter_schema_blocked`, or
`runtime_durable_adapter_migration_blocked`. Fixture data and env presence are
never promoted to `runtime.liveRuntimeEvidence`.
When the Postgres durable adapter is selected or requested, JSON-RPC
`audit.event.query` and `evidence.record.query` must also honor that durability
gate. If auth, schema, migration, durability-query, or table read-query evidence
is blocked, the method returns a JSON-RPC error with redacted blocker data such
as `adapter: "postgres"`, `durableRequested: true`,
`liveRuntimeEvidence: false`, `secretMaterialRead: false`, and the classified
blocker. It must not
return `events: []`, `records: []`, or `count: 0` on a blocked durable read.
Empty successful result sets are valid only after the durable adapter has
completed the read and the matching durable table rows are actually absent.
If `HWLAB_CLOUD_DB_URL` and `HWLAB_CLOUD_DB_SSL_MODE` are absent, health
reports `db.status: "blocked"`.
If both env vars are present, cloud-api attempts a short read-only TCP
connection to the DB endpoint from the injected runtime env. The health payload
keeps all endpoint details redacted and reports only:
The runtime DB readiness authority is the host parsed from the injected
`HWLAB_CLOUD_DB_URL` Secret value. Health reports this as
`db.endpointSource: "secret-url-host"` without printing the host, username,
password, or full URL. The `cloud-api-db` name is only an optional future alias;
it is not the TCP probe target and a missing alias must not reverse-fail live DB
success from the Secret URL host.
`.invalid` hosts, including `hwlab-dev-db.invalid`, are forbidden as DEV
runtime targets and may be used only as negative fixtures.
- `db.configReady`: required env names are present.
- `db.endpointSource`: `secret-url-host`, the authoritative redacted TCP dial
target parsed from `HWLAB_CLOUD_DB_URL`.
- `db.optionalPublicDnsAlias`: diagnostic metadata for the non-authoritative
`cloud-api-db` alias; `requiredForReadiness` and `usedForProbe` stay false.
- `db.connectionAttempted`: the runtime tried the live connection path.
- `db.connectionResult`: redacted classifier such as `connected`, `refused`,
`timeout`, `dns_error`, `invalid_url`, or `unsupported_protocol`.
- `db.liveConnected`: the TCP connection completed.
- `db.liveDbEvidence`: true only when the live connection completed; env
presence, fixtures, and disabled probes must keep this false.
- `db.redaction` and `db.safety`: confirm values/endpoints are redacted and
secret material was not read by the health path.
- `db.readinessLayers`: records DNS, TCP, auth, and schema status separately so
DNS/TCP repair cannot be confused with authenticated schema readiness.
- `db.ready`: currently aliases `db.liveConnected`.
Env presence alone is not treated as green. If the runtime has env injection
but `db.connectionAttempted` is false, `db.liveConnected` is false, or
`db.liveDbEvidence` is false, the gate must stay blocked/degraded with the
reported blocker.
Fixture: `fixtures/cloud-api-runtime/minimal-runtime.json`.
## Code Agent Provider Boundary
`hwlab-cloud-api` supports OpenAI Responses for the Code Agent chat endpoint.
DEV source contracts require `OPENAI_API_KEY` from Secret
`hwlab-code-agent-provider/openai-api-key` and
`HWLAB_CODE_AGENT_OPENAI_BASE_URL` through the DEV egress/proxy URL. Runtime
health and `/v1` may report provider status, missing env names, Secret ref
names, model, and redacted egress status, but must never print the API key or a
Bearer token.
-169
View File
@@ -1,169 +0,0 @@
# HWLAB Cloud Workbench Frontend Contract
This document is the review contract for
`DC-DCSN-P0-2026-003`, `pikasTech/HWLAB#99`, and
`pikasTech/HWLAB#78`. It defines the Cloud Workbench frontend design and
acceptance surface for later implementation. It is documentation-only: it does
not authorize deployment, service restart, PROD access, heavyweight browser
automation, or hardware mutation.
The default Cloud Web experience may be rebuilt from scratch to satisfy this
contract. Existing Gate or M3 diagnostics screens from `#59` are not the
default homepage contract.
## Product Position
Cloud Workbench is the default browser entry at
`http://74.48.78.17:16666`. It should feel like a VS Code-style operator
workbench for HWLAB DEV: resources on the left, agent conversation and trace in
the center, evidence and hardware context on the right, and commands at the
bottom.
The workbench is a read-only or dry-run coordination surface until a later
contract explicitly enables a narrow write path. It must not become a generic
hardware control panel.
## Route Structure
The frontend route model must keep the workbench as the default route and move
diagnostics under secondary routes:
| Route | Purpose | Default | Source boundary |
| --- | --- | --- | --- |
| `/` | Cloud Workbench default. Shows agent conversation, trace, selected resource context, hardware/evidence side panel, and command input. | Yes | Same-origin `/v1`, read-only `/json-rpc`, source/gate report, blocked report. |
| `/workbench` | Explicit alias for the default workbench. | Yes, alias | Same as `/`. |
| `/gate` | Internal static alias for the read-only gate diagnostics view. | No | Same as `/diagnostics/gate`; source/gate report and same-origin read-only diagnostics only. |
| `/diagnostics` | Secondary diagnostics hub that links to status and gate views. | No | Same-origin `/v1` and report fixtures only. |
| `/diagnostics/status` | Read-only DEV status: edge, router, API, web, DB readiness, agent service health, and artifact identity. | No | Same-origin `/v1/status` or equivalent read-only status endpoint. |
| `/diagnostics/gate` | Read-only gate and M3 diagnostics inherited from `#59`: topology, route, health, blockers, and evidence summary. | No | Gate report and blocked report; read-only `/json-rpc` only when already defined. |
| `/agents` | Agent sessions, workers, skills, trace timeline, and cleanup status. Can be a focused view or a left-rail activity inside `/`. | No | Same-origin `/v1` agent summaries and source report. |
| `/hardware` | Hardware resources, gateway sessions, patch-panel topology, box simulators, capabilities, and blockers. | No | Read-only `/json-rpc` status/list methods and same-origin `/v1` summaries. |
| `/records` | Trusted records: evidence, audit, trace, operation IDs, artifact tag/commit/digest, and report links. | No | Gate report, source report, blocked report, and same-origin `/v1` summaries. |
The route relationship is:
- `/` and `/workbench` are the primary product surface.
- `/gate` is a short internal alias for the same hidden gate view as
`/diagnostics/gate`; it must not become the default route.
- `diagnostics/status` and `diagnostics/gate` are auxiliary views for
troubleshooting and acceptance review.
- Agent, hardware resources, and trusted records are first-class workbench
domains. They may be implemented as routes, tabs, or focused activity-rail
modes, but the default route must show how they relate to each other.
- `#59` diagnostics remain available under `/diagnostics/gate`; they must not
define the default homepage.
## Layout Structure
The default workbench layout must use four stable regions:
| Region | Required content | Required behavior | `sourceKind` labels |
| --- | --- | --- | --- |
| Left activity rail and resource tree | Activity icons for Workbench, Agent, Hardware, Records, Diagnostics; resource tree for project, gateway sessions, patch-panel, box resources, capabilities, agent sessions, workers, and reports. | Selecting an item changes the center and right-panel context without implying mutation. Unknown or blocked items remain visible with disabled actions. | `SOURCE`, `DRY-RUN`, `DEV-LIVE`, `BLOCKED`. |
| Center agent conversation and trace | Agent conversation stream, plan/trace events, selected operation timeline, agent/worker/session IDs, and blocker messages. | Conversation input defaults to no-mutation guidance. Any future action that could mutate hardware is disabled unless a later contract explicitly enables it. Trace rows are clickable and open evidence context. | `SOURCE`, `LOCAL`, `DRY-RUN`, `DEV-LIVE`, `BLOCKED`. |
| Right hardware/evidence side panel | Selected hardware resource, patch-panel wiring, gateway/box status, evidence record, audit record, operation ID, artifact commit/tag/digest, and report provenance. | Panel is read-only. It explains why an item is blocked, dry-run, source-only, or live. It must not expose generic hardware write controls. | `SOURCE`, `DRY-RUN`, `DEV-LIVE`, `BLOCKED`. |
| Bottom command/input area | Command composer, dry-run preview, selected scope, source boundary, and disabled live controls. | Default mode is read-only or dry-run. Live hardware execution controls are disabled with an explicit blocker reason until a separate acceptance contract permits them. | `DRY-RUN`, `BLOCKED`, optionally `DEV-LIVE` for read-only observations only. |
The UI may use a full rewrite of `web/hwlab-cloud-web`. It should preserve
the public `:16666` entrypoint and same-origin API assumptions rather than the
old diagnostics-first component structure.
## Data Sources
Every visible panel must display or carry a `sourceKind` value. The frontend
must keep these data sources separate:
| Source | Use | Allowed calls | `sourceKind` |
| --- | --- | --- | --- |
| Same-origin `/v1` | Cloud API summaries for status, agents, records, health, artifact identity, and read-only workbench aggregation. | `GET` or documented read-only RPC wrappers through the same origin as the web bundle. | `DEV-LIVE` only when observed from the real DEV route; otherwise `BLOCKED` or `SOURCE`. |
| Read-only `/json-rpc` | Hardware/gateway/patch-panel status, capabilities, topology, and evidence lookups already defined as safe reads. | Only list/status/get/describe methods. No generic write, no direct box mutation, no bypass of patch-panel ownership. | `DEV-LIVE` for read-only real DEV observations; `DRY-RUN` for fixture-backed previews. |
| Source report | Checked-in contracts, manifests, schemas, service IDs, and documentation. | Static fetch or bundled build asset only. | `SOURCE`. |
| Gate report | `/tmp/hwlab-dev-gate` gate summaries, DEV layer status, artifact identity, and M3/M4/M5 readiness. | Read-only local report content or same-origin report endpoint. | `SOURCE`, `DRY-RUN`, `DEV-LIVE`, or `BLOCKED` exactly as reported. |
| Blocked report | Open blockers for DB, M3, M4, edge/route, artifacts, registry, and evidence gaps. | Read-only report content or same-origin summary endpoint. | `BLOCKED`. |
The frontend must not infer `DEV-LIVE` from successful page load on `:16666`.
`DEV-LIVE` requires an observation from the real DEV route for the specific
thing being displayed.
## Status Labels
Use these labels consistently:
| Label | Meaning | UI rule |
| --- | --- | --- |
| `SOURCE` | Repository documentation, schemas, source fixtures, manifests, or checked-in reports. | May be shown as design/contract readiness only. Never claim live state. |
| `LOCAL` | Localhost or in-process smoke result. | May appear in trace or acceptance summaries, but not as live DEV evidence. |
| `DRY-RUN` | Fixture-backed or no-mutation preview. | Command previews and agent plans default here. Must state that no DEV/PROD state changed. |
| `DEV-LIVE` | Read-only observation from the real DEV route for the exact component, record, or route shown. | May mark edge, API, DB, artifact, agent, or hardware status only when supported by specific evidence. |
| `BLOCKED` | Missing, stale, unsafe, or not-yet-authorized evidence or action. | Must show blocker reason and keep unsafe or unproven controls disabled. |
The UI must never upgrade `SOURCE`, `LOCAL`, `DRY-RUN`, edge-only, or
front-end-only observations into M3 or M4 `DEV-LIVE`.
## Interaction Boundaries
Allowed interactions for this contract:
- Navigate routes and activity rail modes.
- Select project, gateway, box, patch-panel, capability, agent, worker,
evidence, audit, trace, operation, and report records.
- Refresh read-only `/v1` status, read-only `/json-rpc` status/list/get
methods, source reports, gate reports, and blocked reports.
- Compose a command and view a dry-run preview with selected scope, expected
evidence, and blocker reasons.
- Copy IDs, links, commands, and report references.
Disabled in the first workbench implementation:
- Run live agent hardware operations.
- Change patch-panel wiring.
- Write box, gateway, simulator, or hardware state.
- Start or stop gateway, worker, tunnel, edge, router, API, web, DB, or PROD
services.
- Deploy images, apply manifests, restart services, read secrets, or run
heavyweight e2e/Playwright flows.
- Mark M3, M4, or M5 accepted from the browser.
Future buttons may be visible only if they are disabled and explain the
required contract, for example `BLOCKED: live command requires M0-M5 gate,
DEV-only authorization, and patch-panel-owned operation evidence`.
Do not add a generic hardware command form. Any future write path must be
narrow, named, patch-panel owned, audited, evidenced, DEV-only, and covered by
a new acceptance contract.
## Relationship To `#59`
`#59` defined a read-only diagnostics console for M3 topology, route, health,
blockers, and evidence summary. For `#99`, that surface is retained as
`/diagnostics/gate` and may also appear as a Diagnostics activity in the left
rail.
`#59` must not define `/`, `/workbench`, product navigation, or the default
homepage. The default homepage is the Cloud Workbench described here.
The `npm run web:m3-readonly` guard remains useful as a safety check for the
diagnostics route and same-origin read-only boundary. A later implementation
may update the script to reflect the new workbench route model, but it must
continue to fail on hardware write APIs, public endpoint drift, and evidence
misclassification.
## DEV Acceptance Contract
Acceptance for the frontend design and later implementation is:
| Area | Acceptance |
| --- | --- |
| Default page | `http://74.48.78.17:16666/` opens the Cloud Workbench, not the Gate/M3 Diagnostics dashboard; its first screen does not show Gate, `BLOCKED`, `M0-M5`, or acceptance-review copy. |
| API status | `http://74.48.78.17:16667` remains the DEV API/edge/status boundary; browser code uses same-origin `/v1` for workbench data and only read-only `/json-rpc` methods for diagnostics/hardware status. |
| Routes | `/`, `/workbench`, `/gate`, `/diagnostics`, `/diagnostics/status`, `/diagnostics/gate`, Agent, hardware resources, and trusted records are represented in navigation or route aliases. |
| Layout | Left activity rail/resource tree, center agent conversation/trace, right hardware/evidence side panel, and bottom command/input area are present on the default workbench. |
| Labels | `SOURCE`, `LOCAL`, `DRY-RUN`, `DEV-LIVE`, and `BLOCKED` labels are visible where evidence state is shown and follow the rules above. |
| Read-only boundary | Hardware resources and diagnostics are read-only. Live controls are disabled with blocker reasons. |
| Browser smoke | A lightweight screenshot/manual browser smoke may verify that the default page loads, the workbench regions are visible, diagnostics is secondary, and no text or controls imply generic hardware writes. |
| Artifact identity | Acceptance notes must include web image tag, commit, digest or `not_applicable` reason, build source, deploy environment, and health timestamp when runtime evidence is claimed. |
| Blocker display | DB, M3, and M4 blockers must be displayed separately when present. DB readiness cannot green M3/M4; edge route live cannot green DB, M3, or M4. |
This document does not require a heavy check or browser e2e run. For the
documentation PR, the minimum validation is `git diff --check` and an `rg`
scan for the task terms and frozen labels.
-57
View File
@@ -1,57 +0,0 @@
# D601 k3s Readonly Observability
This entry point supports `pikasTech/HWLAB#46` and the DEV runtime blockers in
`#7`, `#33`, `#36`, `#38`, `#39`, and `#42`. It is a read-only preflight for
the D601 Code Queue runner and the `hwlab-dev` namespace.
It does not authorize PROD, read Secret resources, print kubeconfig/token
material, print ConfigMap values, mutate cluster state, restart runtime
services, or run heavy checks on the master server.
## Command
Run from the repository root:
```sh
node --check scripts/d601-k3s-readonly-observability.mjs
node --check scripts/src/d601-k3s-readonly-observability.mjs
node scripts/d601-k3s-readonly-observability.mjs
```
The command writes `/tmp/hwlab-dev-gate/d601-k3s-readonly-observability.json` and prints a
short JSON summary. A `blocked` conclusion means the preflight ran and recorded
the missing binary, kubeconfig path, SSH bridge, or read permission. Use
`--fail-on-blocked` only in CI jobs that should fail when observability is not
ready.
Useful options:
```sh
node scripts/d601-k3s-readonly-observability.mjs --pretty
node scripts/d601-k3s-readonly-observability.mjs --timeout-ms 5000
node scripts/d601-k3s-readonly-observability.mjs --no-write
node scripts/d601-k3s-readonly-observability.mjs --report /tmp/hwlab-dev-gate/d601-k3s-readonly-observability.json
```
## What It Checks
- `kubectl`, `k3s`, `k3sctl`, and `ssh` availability and version output.
- `KUBECONFIG`, `~/.kube/config`, `/etc/rancher/k3s/k3s.yaml`, and the k3s
admin kubeconfig path by file metadata only.
- SSH maintenance bridge hints from known environment variable names and
`~/.ssh` metadata only.
- If a Kubernetes executor is available, read-only access to `hwlab-dev`
namespace, pods, services, and ConfigMaps.
- Summaries for pods, services, and ConfigMap key names only. ConfigMap data
values are not printed.
## Ready Criteria
`ready` requires a direct executor, such as `kubectl` or `k3s kubectl`, to read
pods, services, and ConfigMaps from `hwlab-dev` and no open environment or
observability blocker.
`blocked` keeps the report consumable by follow-up issues. The report includes
open blockers with `scope`, `summary`, and `nextTask` fields so runner image or
mount work can be tracked without guessing which binary, permission, or path is
missing.
-150
View File
@@ -1,150 +0,0 @@
# HWLAB DEV Acceptance Matrix
This matrix is the DEV acceptance contract for the MVP runtime. It is scoped to
static review and lightweight smoke checks only. It does not authorize a real
DEV or PROD deployment.
## Fixed Boundary
- DEV frontend endpoint: `http://74.48.78.17:16666`
- DEV API/edge endpoint: `http://74.48.78.17:16667`
- Deploy environment: `dev`
- Legacy public endpoints `:6666` and `:6667` are deprecated; browser entry
is `:16666` and API/health entry is `:16667`.
- Internal k3s service ports may still use `6667`, for example
`hwlab-cloud-api` and `hwlab-edge-proxy`. Internal `6667` is not a public
DEV acceptance endpoint.
- Runtime route: client, master `hwlab-edge-proxy`, `frp`, D601
`hwlab-dev/hwlab-router`, then HWLAB cloud/runtime services.
- UniDesk backend, provider-gateway, and microservice proxy are not accepted as
substitutes for HWLAB runtime services in this first version. They may remain
external scheduling, CI, or CD support only.
## M3 Evidence Classification
Current P0 DEV acceptance remains the M3 virtual hardware trusted loop: two
`hwlab-box-simu` instances, two `hwlab-gateway-simu` instances, and one
`hwlab-patch-panel`.
`M3 live` can be claimed only when a DEV observation proves the live
`res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1` path and records
the operation, trace, audit, and evidence identifiers. The patch panel must
own the route decision; direct box-to-box propagation or fixture output is not
M3 live evidence.
`M3 support` includes this endpoint freeze, read-only public edge curl
evidence, source contracts, static manifest cardinality, local smoke output,
and dry-run fixtures. These items support release or pre-release decisions, but
they are not P0 live acceptance.
`Non-P0` includes SOURCE, LOCAL, DRY-RUN, fixture-only, diagnostic, and
edge-only observations that do not prove the full
`res_boxsimu_1 -> hwlab-patch-panel -> res_boxsimu_2` link. These observations
must not be written as `DEV-LIVE`.
## Required Artifact Observability
Every deployable HWLAB artifact that participates in DEV acceptance must expose
or be joined with these fields:
| Field | Requirement |
| --- | --- |
| `serviceId` | One of the frozen HWLAB service IDs. |
| `commitId` | Git commit that produced the artifact, short or full SHA. |
| `image` | Image repository/name when containerized, or package artifact name for non-container artifacts. |
| `tag` | Immutable or traceable tag, preferably including the commit. |
| `digest` | Content digest when the artifact is an image or build output that supports digests. |
| `buildSource` | Source repository, branch/ref, and build workflow or local command. |
| `deployEnv` | Must be `dev` for this matrix. |
| `healthTimestamp` | ISO-8601 timestamp from the health observation or smoke collector. |
Missing `digest` is allowed only for non-container client assets or local dry-run
artifacts, and must be recorded as `not_applicable` with a reason.
## Health Contract
All health responses must be JSON, include `serviceId`, identify `dev`, and
provide a current health timestamp. Existing skeleton services may expose
`observedAt`; the acceptance collector maps it to `healthTimestamp`.
| Component | Service ID | Check | Success | Failure |
| --- | --- | --- | --- | --- |
| DEV API/edge ingress | `hwlab-edge-proxy` | `GET http://74.48.78.17:16667/health` or routed service health | HTTP 2xx/3xx reaches HWLAB DEV path and reports edge identity or downstream HWLAB identity | Timeout, non-HWLAB response, PROD route, missing artifact fields |
| master edge proxy | `hwlab-edge-proxy` | Edge proxy health and route table observation | Route for `http://74.48.78.17:16667` forwards to `frp` and identifies commit/image | No DEV route, wrong port, missing route observability |
| frp tunnel | `hwlab-tunnel-client` | Tunnel session/status observation | Tunnel for DEV route is established to D601 router and identifies commit/image | Tunnel down, wrong target, ambiguous service identity |
| D601 router | `hwlab-router` | `hwlab-dev/hwlab-router` health/status | Router is live, environment is `dev`, route target is cloud API/web or runtime service | Namespace mismatch, route missing, stale health timestamp |
| Cloud API | `hwlab-cloud-api` | `GET /health`, `GET /live`, optional JSON-RPC `/rpc` probe | Returns service ID, `dev`, healthy/live status, redacted DB env readiness, and accepts a harmless protocol probe | HTTP error, unknown service ID, wrong environment, invalid JSON-RPC envelope, missing DB env readiness |
| Cloud Web | `hwlab-cloud-web` | `GET http://74.48.78.17:16666/`, static asset check, and the workbench contract in `docs/cloud-web-workbench.md` | Public browser entry serves the Cloud Workbench on `:16666`; default page is a VS Code-style workbench with left activity rail/resource tree, center Agent conversation/trace, right hardware/evidence side panel, and bottom command/input area; API/edge status remains on `http://74.48.78.17:16667`; browser data uses same-origin `/v1`, read-only `/json-rpc`, source/gate report, and blocked report with explicit `sourceKind` labels | Endpoint drift, public web served from `:6667`, Gate/M3 Diagnostics used as default homepage, direct write/control endpoint text or calls, missing `SOURCE`/`DRY-RUN`/`DEV-LIVE`/`BLOCKED` labeling, edge-only evidence presented as M3 `DEV-LIVE`, missing asset |
| Agent manager | `hwlab-agent-mgr` | Agent scheduling health/status | Reports live manager, commit/image, and DEV environment; no worker leak after smoke | Scheduler unavailable, wrong environment, unbounded worker session |
| Agent worker | `hwlab-agent-worker` | Worker health/status during dry-run or scoped smoke | Worker session is scoped to DEV project and emits trace/audit identifiers | Missing session identity, unsafe mutation, cleanup failure |
| Agent skills | `hwlab-agent-skills` | Skill bundle version/status | Skill artifact is traceable to commit/build source and compatible with worker | Unversioned skill bundle, missing build source |
| Gateway | `hwlab-gateway` | `GET /health/live` and `GET /status` when present | Reports DEV gateway boundary and does not bypass patch-panel constraints | Hardware boundary unavailable, non-DEV gateway, direct box mutation |
| Gateway simulator | `hwlab-gateway-simu` | `GET /health/live`, `GET /status`, `GET /boxes` | Simulator is live, lists expected box resources, and identifies DEV project; this is M3 support until paired with the full patch-panel link observation | Simulator down, box list missing, stale timestamp |
| Box simulator | `hwlab-box-simu` | `GET /health/live`, `GET /status` | Simulator is live and reports resources, ports, and patch-panel-only propagation; this is M3 support until paired with the full patch-panel link observation | Cross-device propagation outside patch panel, missing resource state |
| Patch panel | `hwlab-patch-panel` | `GET /health/live`, `GET /status`, `GET /wiring` | Wiring config is parseable and patch-panel state owns routing decisions; M3 live also requires a traced `DO1 -> patch-panel -> DI1` operation | Invalid topology, direct bypass path, stale patch state |
| CLI | `hwlab-cli` | `npm run cli:health` and dry-run command | CLI uses DEV endpoint and dry-run states no DEV/PROD changes were made | Wrong endpoint, missing dry-run guard, real mutation attempted |
## DEV Smoke Matrix
The smoke sequence must run in order and stop on the first critical blocker.
Network checks may be replaced by recorded observations when the runner cannot
reach the DEV host, but replacement evidence must include the artifact fields
listed above.
Cloud Web workbench smoke is covered by:
- `node scripts/dev-cloud-workbench-smoke.mjs --static`
- `node scripts/dev-cloud-workbench-smoke.mjs --dom-only --url http://74.48.78.17:16666/`
- `node scripts/dev-cloud-workbench-smoke.mjs --live --url http://74.48.78.17:16666/`
The static mode is SOURCE-level contract evidence only and must report
`devLive=false`; it cannot promote SOURCE, LOCAL, DRY-RUN, or fixture evidence
to DEV-LIVE. It observes the PR #114 Markdown help surface as ready when
`web/hwlab-cloud-web/help.md`, the vendored `marked` renderer, and the
non-default internal help route are present. The `--dom-only` mode is a
live-read-only DOM validation path: it preserves runtime/web-asset identity
preflight semantics, may still inspect deployed DOM wiring after identity drift,
and records Code Agent as `not_applicable` without sending `/v1/agent/chat`.
The live mode is optional read-only HTTP plus browser DOM observation and must
report `blocked` or `skip` structure instead of a false green when the browser
check is unavailable.
| Step | Probe | Success Criteria | Failure Criteria | Blocker Class |
| --- | --- | --- | --- | --- |
| 1 | Confirm repository contract files and JSON checklist parse. | `docs/dev-acceptance-matrix.md` exists and `docs/dev-acceptance-checklist.json` parses. | Missing file or invalid JSON. | `contract_blocker` |
| 2 | Verify frozen DEV endpoints. | Public frontend is exactly `http://74.48.78.17:16666`; public API/edge is exactly `http://74.48.78.17:16667`; internal `6667` appears only as a k3s service/listen port. | Any alternate public DEV endpoint, old public `:6667`, or PROD target. | `environment_blocker` |
| 3 | Observe DEV API/edge ingress health. | Request reaches HWLAB DEV route and returns HWLAB identity or accepted downstream health. | Timeout, non-HWLAB target, wrong public port. | `network_blocker` |
| 4 | Observe master edge proxy route. | Edge route maps DEV endpoint to `frp` and records artifact identity. | Missing route, stale route, missing artifact identity. | `network_blocker` |
| 5 | Observe `frp` tunnel. | Tunnel links master edge to D601 router for DEV. | Tunnel down or target mismatch. | `network_blocker` |
| 6 | Observe D601 `hwlab-dev/hwlab-router`. | Router is live and forwards only to HWLAB DEV services. | Namespace mismatch or route bypass. | `runtime_blocker` |
| 7 | Check cloud API/web surface. | Cloud API health is valid on public `:16667`; web assets are served on public `:16666`; Cloud Web default route is the Cloud Workbench defined in `docs/cloud-web-workbench.md`; diagnostics/status/gate are secondary; data sources are same-origin `/v1`, read-only `/json-rpc`, source/gate report, and blocked report; `npm run web:m3-readonly` or its workbench-aware successor passes. | Bad health, endpoint drift, Gate/M3 Diagnostics used as default homepage, direct hardware write/control surface from web, missing source labels, or edge-only evidence promoted to M3 `DEV-LIVE`. | `runtime_blocker` |
| 8 | Check gateway, simulator, box simulator, and patch-panel contracts. | Health/status JSON is parseable and topology keeps routing under patch-panel ownership; for M3 live, a traced `DO1 -> patch-panel -> DI1` operation exists. | Missing health, invalid topology, bypass path, or any attempt to promote support/fixture evidence to M3 live. | `runtime_blocker` |
| 9 | Check agent manager, worker, and skills contracts. | Agent artifacts are traceable; dry-run/scoped smoke emits session, trace, audit, and cleanup evidence. | Missing traceability, unsafe mutation, cleanup leak. | `agent_blocker` |
| 10 | Verify evidence and artifact observability. | Every accepted artifact has service ID, commit, image/tag/digest or reason, build source, env, and health timestamp. | Missing required observability field. | `observability_blocker` |
## Pass And Fail Rules
The matrix passes only when every smoke step is either observed as successful or
explicitly marked not applicable with a non-production reason. A step is failed
when the observed result contradicts a frozen contract, cannot be parsed, or
cannot be tied to a traceable HWLAB artifact.
M3 live cannot be inferred from SOURCE, LOCAL, DRY-RUN, edge-only, or
front-end-only evidence. If the evidence does not show the operation, trace,
audit, and evidence IDs on the `res_boxsimu_1 -> hwlab-patch-panel ->
res_boxsimu_2` chain, it is not a pass.
Critical blockers are `contract_blocker`, `environment_blocker`,
`network_blocker`, `runtime_blocker`, `agent_blocker`,
`observability_blocker`, and `safety_blocker`. A `safety_blocker` must be raised
for any attempted PROD deployment, real deployment from this matrix, secret
read, heavyweight e2e run, or UniDesk runtime substitution.
## First Version Exclusions
- No PROD deployment or PROD smoke.
- No real DEV deployment from this document.
- No heavyweight e2e or destructive hardware action.
- No secret or token reads.
- No replacement of HWLAB runtime services by UniDesk backend,
provider-gateway, or microservice proxy.
-142
View File
@@ -1,142 +0,0 @@
# HWLAB DEV Base Image Preflight
This preflight is the lightweight builder gate for DEV artifact publish work. It
checks whether the D601 builder has an approved local base image before any
artifact publish attempt claims readiness.
The command is local-only. It does not pull, build, push, deploy, contact DEV or
PROD, read secrets, or use UniDesk runtime services as substitutes.
## Current Repository Constraints
- No repository Dockerfile is present in the DEV skeleton.
- `deploy/artifact-catalog.dev.json` pins service image names to the DEV
registry target, by default
`127.0.0.1:5000/hwlab/<hwlab-service-id>:<commit>`; `deploy/deploy.json`
remains human-authored runtime config and must not carry generated image
identity.
- The artifact catalog may be either `contract-skeleton` or `published`. A
`published` catalog must be backed by `/tmp/hwlab-dev-gate/dev-artifacts.json`
with real `sha256:<64 hex>` digests for every required service.
- The catalog and runtime boundary forbid PROD deployment, secret reads, force
push, real publish claims, and UniDesk runtime substitution.
- A builder base image is separate from HWLAB service artifact images. This
preflight only decides whether #35 may proceed to build/publish; it does not
prove that any service image was published.
Committed artifact reports may record successful base-image and publish evidence
for an older source commit. Compare their source commit with the desired-state
commit before using them for refresh or apply review. A failed catalog manifest
read from a runner process is a registry reachability question for `#66`, not
proof that the base image or publish digests are missing.
## Command
```sh
npm run --silent dev-base-image:preflight
```
Equivalent direct command:
```sh
node scripts/preflight-dev-base-image.mjs
```
The direct command always prints JSON. Use `npm run --silent` when npm is the
entry point and the output needs to be machine parsed. Exit code `0` means
`status: "ready"` and the base image can be used by #35 DEV artifact publish.
Exit code `2` means `status: "blocked"` and artifact publish must stop.
## Image Selection
Selection order is intentionally narrow:
1. If `HWLAB_DEV_BASE_IMAGE` is set, it must name an approved image that already
exists in the local Docker image cache.
2. If `HWLAB_DEV_BASE_IMAGE` is not set, the preflight looks for local
`node:20-*` images and selects the first deterministic local tag.
3. If no `node:20-*` tag exists, the preflight also accepts a local HWLAB base
tag such as `127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim`.
4. If neither source is available, the result is a blocker.
Explicit base image values must match local `node:20-*`, `hwlab-dev-base:*`,
`hwlab-node20-base:*`, or `hwlab-node-runtime-base:*` references. They must not
reference UniDesk, Code Queue, `backend-core`, `provider-gateway`,
`microservice-proxy`, or an HWLAB runtime service image. A service image such as
`127.0.0.1:5000/hwlab/hwlab-cloud-api:<sha>` is an artifact output, not a
builder base image.
The recommended D601 preload source is `node:20-bookworm-slim`. The recommended
HWLAB-specific local tag is:
```sh
127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim
```
## Output Contract
Important fields:
| Field | Meaning |
| --- | --- |
| `status` | `ready` or `blocked`. |
| `imageSource` | `env:HWLAB_DEV_BASE_IMAGE`, `local-docker-node:20-*`, or `none`. |
| `requestedImage` | The explicit environment value, when present. |
| `localTag` | Local Docker tag selected for the builder base image. |
| `imageId` | Local Docker image ID from `docker image inspect`. |
| `candidates` | Approved local builder base images found in Docker. |
| `rejectedCandidates` | Near misses such as local non-Node-20 Node images. |
| `publishUsable` | Boolean gate for #35 artifact publish. |
| `blockers` | Deterministic reasons artifact publish must stop. |
| `nextSteps` | Operational fixes that do not require secret reads or runtime substitution. |
| `recommendation` | Machine-readable recommended source, env var, and base image tags. |
| `provision` | Copy-pasteable online, HWLAB-tag, offline import, and dry-run commands. |
| `blockedReport` | Minimal machine-readable blocked report: exact blocker, expected tag, env value, and next preload command. |
## Blocker Handling
When blocked, preload or build an approved DEV builder base image into the D601
Docker cache, set `HWLAB_DEV_BASE_IMAGE` to the exact local tag if it is not a
`node:20-*` tag, and rerun the preflight. Do not claim artifact publish success
until the preflight returns `status: "ready"`.
Online D601 preload:
```sh
docker pull node:20-bookworm-slim
HWLAB_DEV_BASE_IMAGE=node:20-bookworm-slim node scripts/preflight-dev-base-image.mjs
```
Optional HWLAB-local tag provision:
```sh
docker pull node:20-bookworm-slim
docker tag node:20-bookworm-slim 127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim
HWLAB_DEV_BASE_IMAGE=127.0.0.1:5000/hwlab/hwlab-dev-base:node20-bookworm-slim node scripts/preflight-dev-base-image.mjs
```
Optional dependency runtime base provision:
```sh
node scripts/dev-runtime-base-image.mjs --dry-run
node scripts/dev-runtime-base-image.mjs
HWLAB_DEV_BASE_IMAGE=127.0.0.1:5000/hwlab/hwlab-node-runtime-base:deps-<hash> node scripts/preflight-dev-base-image.mjs
```
This runtime base caches `package.json` / `package-lock.json` dependencies in
`/opt/hwlab-node-runtime-base/node_modules`. Service artifact builds copy that
directory when present, which avoids repeating the same `npm ci` layer for each
service.
Offline preload path when D601 cannot pull directly:
```sh
docker pull node:20-bookworm-slim
docker save node:20-bookworm-slim -o hwlab-node20-bookworm-slim.tar
docker load -i hwlab-node20-bookworm-slim.tar
HWLAB_DEV_BASE_IMAGE=node:20-bookworm-slim node scripts/preflight-dev-base-image.mjs
```
The preflight may use UniDesk and Code Queue as scheduling infrastructure only.
It must not use their runtime images as HWLAB service images or builder base
image substitutes.
-113
View File
@@ -1,113 +0,0 @@
# HWLAB DEV Edge Health
This check is DEV-only and targets the frozen endpoint:
```sh
node scripts/dev-edge-health-smoke.mjs --live --report /tmp/hwlab-dev-gate/report.json
```
The smoke is read-only. It does not touch PROD, restart services, read
secrets, or substitute UniDesk backend/provider-gateway/microservice-proxy for
HWLAB runtime.
## Health Evidence
`GET http://74.48.78.17:16667/health` must return HWLAB DEV JSON with:
- `serviceId` for the HWLAB service answering the request;
- `environment: "dev"`;
- `commit` evidence;
- `image` evidence;
- `service` evidence.
`hwlab-cloud-api` also serves `GET /health/live` for k3s probes and edge
forwarding checks.
`db` in the cloud-api health payload is a redacted configuration gate. It
reports required env names, presence, missing names, and Secret reference names
only. Runtime health additionally reports redacted DB readiness layers:
`configReady`, `envInjected`, `endpointSource`, `connectionAttempted`,
`connectionResult`, and `liveConnected`. It must not expose a connection
string, token, password, DB host, username, or claim fixture output as live DB
evidence.
Required DEV DB config names:
- `HWLAB_CLOUD_DB_URL` from Secret reference
`hwlab-cloud-api-dev-db/database-url`.
- `HWLAB_CLOUD_DB_SSL_MODE=disable`.
- Runtime TCP dial target: the redacted host parsed from
`HWLAB_CLOUD_DB_URL`, reported as `endpointSource="secret-url-host"`.
`cloud-api-db` is only an optional desired alias. Until this repo owns the
Service plus Endpoint or EndpointSlice manifests and rollout/apply contract, it
is not a readiness authority, is not the TCP probe target, and a missing alias
must not reverse-fail live DB success from the Secret URL host.
When the Secret/env is absent, the health JSON should keep
`db.connected: false`, set `db.status: "blocked"`, and list the missing env
names so gate reports can identify `cloud-api-db-health-gate`. When the env is
present but no live DB probe is attempted, the gate remains blocked with
`connectionResult: "not_attempted"`. When a probe is attempted but
`liveConnected` is false, the gate remains blocked/degraded with the redacted
connection classifier. `connectionResult: "dns_error"` with
`classification: "dns_resolution_failed"` means DB endpoint DNS failed from the
cloud-api runtime for the Secret URL host. Env presence alone is not live DB
evidence.
The Code Agent provider Secret for #143 is a separate blocker. The edge-health
report may record only key-presence evidence for
`hwlab-code-agent-provider/openai-api-key` and runtime error classification such
as `provider_secret_missing`; it must not read or print provider Secret values.
Do not collapse this #143 provider Secret gap into the DB live blocker.
## Route Classification
The smoke classifies failures into these blockers:
- `frp_blocker`: public `:16667` is unavailable and frps control or tunnel
health ports also refuse connections.
- `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
as a port/network path.
- `app_health_blocker`: public HTTP reaches an app but health JSON is wrong,
missing evidence, returns an HTTP error, or reports DB env injected without a
live DB connection.
## Machine-Readable Diagnosis
Blocked `frp_blocker` and `edge_proxy_blocker` reports now include a
`diagnosis` object in `/tmp/hwlab-dev-gate/dev-edge-health.json` with:
- `likelyLayer`: the most likely broken layer, such as `master-edge/frps`;
- `confidence`: coarse confidence for the diagnosis;
- `likelyCause`: a single-sentence blocker summary;
- `evidence`: the TCP probes that support the diagnosis;
- `notProven`: layers this probe did not rule out;
- `nextTask`: the smallest read-only follow-up or ops action.
## Current Blocker
The committed report at `/tmp/hwlab-dev-gate/dev-edge-health.json` records a
read-only live run where public `http://74.48.78.17:16667/health/live` returned
HWLAB DEV health from `hwlab-cloud-api`, DB config was present, and runtime
health attempted a redacted TCP DB probe. The probe was not connected:
`connected=false`, `liveConnected=false`, `liveDbEvidence=false`,
`connectionResult="dns_error"`, and
`classification="dns_resolution_failed"`. This is a DB live readiness blocker
for #49, not proof that DB is connected.
The same report records the #143 Code Agent provider Secret gap separately as
`provider_secret_missing` when key-presence evidence for
`hwlab-code-agent-provider/openai-api-key` is absent. DB live readiness,
provider-backed Code Agent chat, M3 hardware trusted-loop proof, M4 live agent
loop, and M5 DEV-LIVE acceptance remain separate evidence layers.
## DEV FRP Contract
`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.
-135
View File
@@ -1,135 +0,0 @@
# DEV Evidence / Blocker Aggregator
This is the lightweight report-only entry point for `pikasTech/HWLAB#41` and
the M5 DEV gate aggregator v2 for `pikasTech/HWLAB#58`. It helps a commander
decide whether the DEV acceptance path is green, blocked, or ready for another
repair round across `#33-#39`, `#46`, `#7`, and the MVP DoD in `#9`.
Run from the repository root:
```sh
node scripts/dev-evidence-blocker-aggregator.mjs --pretty
```
For a short validation response:
```sh
node scripts/dev-evidence-blocker-aggregator.mjs --check
```
To refresh the committed v2 machine and human reports:
```sh
node scripts/dev-evidence-blocker-aggregator.mjs --report /tmp/hwlab-dev-gate/report.json
```
The generated files are:
- `/tmp/hwlab-dev-gate/dev-m5-gate-aggregator-v2.json`
- `/tmp/hwlab-dev-gate/dev-m5-gate-aggregator-v2.md`
## Source Levels
The aggregator keeps evidence levels separate so fixture output cannot be
promoted to live DEV evidence:
| Level | Meaning |
| --- | --- |
| `SOURCE` | Repository contracts, schemas, docs, manifests, or examples. |
| `LOCAL` | Localhost or in-process smoke results only. |
| `DRY-RUN` | Fixture-backed or no-mutation dry-run readiness evidence. |
| `DEV-LIVE` | Read-only evidence observed from the real DEV route; this may prove entrypoint reachability without proving downstream DB, M3, M4, or M5 acceptance. |
| `BLOCKED` | Missing issue reads, missing DEV evidence, missing artifacts, or other open blockers. |
## Current DEV Layering
The v2 report exposes `currentDevLayering` so the public route can be green
without promoting the full gate:
| Layer | Meaning |
| --- | --- |
| `Frontend DEV revision` | Latest Cloud Workbench frontend revision visible on the active `http://74.48.78.17:16666/` browser endpoint. While API health or runtime durability is degraded, this may only be summarized as deployed UI usable in degraded/read-only mode; frontend evidence cannot green DB, M3, M4, or M5. |
| `EDGE/ROUTE live` | `16666` browser and `16667` health route evidence from read-only probes. |
| `DB live/degraded` | Cloud API DB readiness from redacted health evidence; route success and env presence do not imply DB live. A `dns_error`/`dns_resolution_failed` DB probe is a DB live blocker. |
| `Code Agent provider Secret` | #143 provider-backed chat readiness from redacted runtime error and Secret key-presence evidence only; missing provider Secret is independent from DB live. |
| `M3 hardware trusted loop` | Real DEV `res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1` plus operation, trace, audit, and evidence identifiers. |
| `M4 agent loop` | Agent loop live preflight and scheduling/evidence closure, gated by DB and runtime readiness. |
| `artifact/desired-state source` | Artifact source coverage for the current target ref plus desired-state dry-run/apply status. |
The report also emits `activeEndpoints` and `deprecatedEndpoints`. Active
acceptance endpoints are:
- frontend/browser: `http://74.48.78.17:16666/`
- API/live: `http://74.48.78.17:16667/health/live`
Legacy public `http://74.48.78.17:6666` and
`http://74.48.78.17:6667` are historical/deprecated only and are not active
green evidence.
`latestFrontendDevFact` records the current #99/#108 frontend visibility fact:
revision `1e8805664970839b72be40c34636b08f6d18b131` is visible on DEV in
degraded/read-only mode, with `promotesM3M4M5=false`.
## Current Contract Map
| Milestone | Current visible level | Contract entry |
| --- | --- | --- |
| M0 | `SOURCE` | `docs/m0-contract-audit.md`, protocol schemas, evidence chain examples, M0 validator. |
| M1 | `LOCAL` | `docs/m1-local-smoke.md`, `fixtures/mvp/runtime.json`, `scripts/m1-contract-smoke.mjs`. |
| M2 | `DEV-LIVE` for frontend/route only | DEV deploy smoke fixture plus active read-only `16666`/`16667` endpoint smoke and degraded/read-only frontend visibility. |
| M3 | `BLOCKED` | Hardware trusted loop topology fixture, local patch-panel smoke, and the no-write DEV plan exist, but DEV-LIVE operation/trace/audit/evidence IDs for `res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1` are missing. |
| M4 | `BLOCKED` | Agent automation loop fixture and local smoke exist, but live preflight is blocked at runtime durable adapter readiness and skills commit/version injection, not stale DB-live readiness. |
| M5 | `BLOCKED` | MVP e2e dry-run plan is green, but bounded DEV-LIVE acceptance is blocked by runtime durable adapter, skills injection, M3/M4, and source/artifact coverage. |
`milestoneLevelClassification` is the compact M0-M5 answer for command
handoff. `milestoneBlockerClassification` gives the M3/M4/M5 blocker class,
dependency, and required next proof.
## Blocker Posture
The v2 report reads committed report fixtures only:
- `/tmp/hwlab-dev-gate/dev-preflight-report.json`
- `/tmp/hwlab-dev-gate/dev-deploy-report.json`
- `/tmp/hwlab-dev-gate/dev-artifacts.json`
- `/tmp/hwlab-dev-gate/dev-edge-health.json`
- `/tmp/hwlab-dev-gate/dev-m2-deploy-smoke-active.json`
- `/tmp/hwlab-dev-gate/dev-m3-hardware-loop.json`
- `/tmp/hwlab-dev-gate/dev-m4-agent-loop.json`
- `GitHub issue/PR comments`
- `/tmp/hwlab-dev-gate/d601-k3s-readonly-observability.json`
The report remains blocked until real DEV-LIVE evidence is attached for the
required downstream HWLAB runtime services. Public route evidence on
`16666/16667` is necessary but not sufficient: DB live readiness, #143 Code
Agent provider Secret readiness, M3 trusted loop evidence, M4 agent-loop
evidence, and artifact/desired-state source coverage stay separate.
The legacy base-image blocker is not current when the committed reports show an
approved Node 20 builder base. Artifact/current remains stricter: a target ref
can still keep `artifact-source-commit` or `dev-artifact-publish` open when it
changes artifact build inputs after the publish source commit, even if the
older DEV artifact report contains 13/13 published service digests. Registry
manifest reachability remains separate and belongs to the #66
process/Docker/k3s access dimensions.
## Next-Round Order
The JSON output groups recommended next actions in dependency order:
1. `d601-k3s`, `kubectl`, kubeconfig/maintenance bridge: restore read-only
hwlab-dev cluster observability without printing Secrets.
2. `cloud-api-db`: prove DEV cloud-api DB env and health readiness with
redacted values only.
3. `dev-edge`, `dev-edge-health`, `dev-ingress-health`: repair
`:16667`/frp/edge/router reachability, then rerun read-only DEV edge health
before M3/M4/M5 live loops.
4. `registry-manifest-read`: resolve #66 registry reachability without
treating it as a missing publish digest or rerunning heavy publish.
## Boundaries
The aggregator does not deploy, call DEV, call PROD, run browser tests, run
heavy e2e, read secrets, restart services, or replace HWLAB runtime services
with UniDesk services. It is a local report generator and static contract
checker only.
-159
View File
@@ -1,159 +0,0 @@
# HWLAB DEV Gate Preflight
This preflight is the read-only gate before a real DEV deploy or DEV smoke on
D601. It decides whether the current `origin/main` can enter the real
`hwlab-dev` runtime path, or whether it is blocked by missing contract,
artifact, cluster, registry, edge, or safety evidence.
It does not authorize PROD, restart runtime services, read secrets or tokens,
substitute UniDesk services for HWLAB runtime, or run heavyweight/browser e2e.
## Command
Run from the repository root:
```sh
node --check scripts/dev-gate-preflight.mjs
node --check scripts/src/dev-gate-preflight.mjs
node --check scripts/src/registry-capabilities.mjs
node --check scripts/deploy-desired-state-plan.mjs
node --check scripts/src/deploy-desired-state-plan.mjs
node --check scripts/dev-runtime-migration.mjs
node --check scripts/src/dev-runtime-migration.mjs
node --check scripts/refresh-artifact-catalog.mjs
node scripts/deploy-desired-state-plan.mjs --target-ref origin/main --check
node scripts/dev-runtime-migration.mjs --check
node scripts/dev-gate-preflight.mjs
```
The command writes `/tmp/hwlab-dev-gate/dev-preflight-report.json` and prints a
short JSON summary. A `blocked` conclusion means the preflight ran correctly but
found blockers; the command exits zero by default so the report can be committed
as evidence. Use `--fail-on-blocked` only in CI jobs that should fail on an open
gate.
Useful options:
```sh
node scripts/dev-gate-preflight.mjs --target-ref origin/main
node scripts/dev-gate-preflight.mjs --report /tmp/hwlab-dev-gate/dev-preflight-report.json
node scripts/dev-gate-preflight.mjs --timeout-ms 5000
node scripts/dev-gate-preflight.mjs --no-write
```
## Read-Only Scope
The preflight checks:
- `deploy/deploy.json` and `deploy/artifact-catalog.dev.json` are internally
consistent and DEV-only.
- `scripts/deploy-desired-state-plan.mjs --target-ref origin/main --check` can
be run as a read-only source support check for deploy commit/image/tag/workload
and env mirror convergence. It does not contact a registry or prove DEV
runtime state.
- The deploy manifest, artifact catalog, catalog service commits, and image tags
are covered by the selected `origin/main` target. If `origin/main` is a
report-only evidence commit whose changes do not touch artifact build inputs,
the preflight may accept the artifact source recorded in
`/tmp/hwlab-dev-gate/dev-artifacts.json`.
- The artifact catalog clearly separates source commit, artifact commit,
`ciPublished`, `registryVerified`, and per-service digest state.
- The artifact catalog has real publish and registry digest evidence, or stays
blocked with `not_published` digests.
- `/tmp/hwlab-dev-gate/dev-artifacts.json`, when present, proves all frozen DEV
service artifacts were published for the selected target or for an artifact
source commit that still covers the target.
- Registry capability evidence is split into `process-http-access`,
`docker-daemon-push-access`, and `k3s-pull-access` instead of one ambiguous
"registry reachable" result.
- `deploy/k8s/base` and `deploy/k8s/dev` parse and remain scoped to
`hwlab-dev`.
- `hwlab-cloud-api` declares the DEV DB env contract:
`HWLAB_CLOUD_DB_URL` from Secret reference
`hwlab-cloud-api-dev-db/database-url` and
`HWLAB_CLOUD_DB_SSL_MODE=disable`. Runtime readiness dials the redacted host
parsed from that Secret URL. `cloud-api-db` is an optional desired alias only
until this repo owns Service plus Endpoint or EndpointSlice manifests and
rollout/apply contract.
- `scripts/dev-runtime-migration.mjs --check` validates the runtime migration
source and ledger contract without live DB access. Live read verification and
migration apply are separate DEV-only modes requiring explicit flags; default
preflight does not read DB secrets or write the DB.
- The local cloud-api health payload reports DB env presence/missing status with
redacted values only. This is a readiness gate, not live DB evidence.
- `deploy/frp` and `deploy/master-edge` describe the D601-to-master DEV route
on public frontend `:16666` and API/edge/live `:16667`. Legacy public
`:6666/:6667` observations are historical/deprecated only and must not be
used as current green evidence or current active blockers.
- The runner can perform read-only `KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl`
probes against `hwlab-dev` and verify node `d601`; default `docker-desktop`
kubeconfig output is not DEV evidence.
- `/tmp/hwlab-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:16667/health/live` responds.
- Catalog image manifests are visible without reading credentials. A failed
manifest read is tracked as a #66 registry reachability dimension and must not
be conflated with missing publish digests.
- Catalog images do not point at UniDesk, provider-gateway, or microservice-proxy
substitutes; `deploy/deploy.json` must not contain generated image identity.
## Registry Capability Dimensions
`registryCapabilities` appears in both the preflight report and the artifact
publish report. The dimensions are:
- `process-http-access`: runner/BuildKit-side HTTP access to `/v2/`. This is
the publish-path registry API preflight for the current BuildKit-based G14
pipeline.
- `docker-daemon-push-access`: read-only Docker daemon evidence for the
local/internal registry target. This is a legacy diagnostic only; it is not a
publish-path capability and must not block BuildKit publish readiness.
- `k3s-pull-access`: read-only native-k3s `kubectl` evidence for whether the
DEV cluster can inspect image pull state. This is the deploy-path capability.
## Verdict Rules
`ready` requires all checks to pass and no open blocker.
`degraded` means a non-required capability is observable but incomplete, such as
legacy Docker daemon registry visibility being unavailable after the G14 publish
path has moved to BuildKit. `blocked` is expected until the required real DEV
runtime path can be proven. Each blocker includes a `type`, `scope`, `summary`,
and `nextTask` so the next task is the smallest repair needed before rerunning
the preflight.
The DB gate has two common blocked scopes:
- `cloud-api-db-env-contract`: manifest/Kubernetes placeholders are incomplete.
The optional `cloud-api-db` alias is not part of this readiness gate.
- `cloud-api-db-health-gate`: runtime env presence is missing. The next task is
to configure the DEV Secret/env names, not to print or commit any secret
value.
For catalog commit mismatch, the preflight emits an
`artifactIdentity.refreshCommands.blocked` command. Use it when the source
commit changed but publish is still blocked:
```sh
node scripts/deploy-desired-state-plan.mjs --target-ref origin/main --pretty
node scripts/refresh-artifact-catalog.mjs --target-ref origin/main --blocked --no-write
```
Only use the published refresh path after `/tmp/hwlab-dev-gate/dev-artifacts.json`
proves every frozen service has a registry digest for that same source commit:
```sh
node scripts/deploy-desired-state-plan.mjs --target-ref origin/main --pretty
node scripts/refresh-artifact-catalog.mjs --target-ref origin/main --publish-report /tmp/hwlab-dev-gate/dev-artifacts.json --no-write
```
Committed DEV artifact reports can prove required service digests only for the
source commit they name. If the selected `origin/main` target drifts onto files
that change artifact build inputs, the preflight can still reopen
`artifact-source-commit` or `dev-artifact-publish` even though the base-image
blocker stays closed. Remaining registry manifest-read failures are #66
reachability evidence, not a reason to reopen the base-image blocker.
This is M3 virtual hardware trusted-loop support only. It does not claim M3
DEV-LIVE unless a real `DO1 -> patch-panel -> DI1` chain is observed through
the current DEV endpoint.
-151
View File
@@ -1,151 +0,0 @@
# HWLAB DEV Gate Report Contract
This document defines the canonical DEV gate report format for
`pikasTech/HWLAB#31` and the DEV deploy apply report extension for
`pikasTech/HWLAB#33`. It is the handoff surface for the parallel workstreams
behind `#7/#9/#12/#17/#20/#21/#22/#23/#24/#25/#26`, so source-contract
evidence, local smoke, dry-run notes, real DEV prerequisites, and remaining
blockers stay in one place.
This contract is report-only. It does not authorize a real DEV or PROD
deployment.
## Report Lifecycle
Each committed DEV gate report must carry `reportLifecycle`:
- `state: "active"` means the report belongs to the current DEV gate surface.
Its `activeEndpoint` must be `http://74.48.78.17:16667`, its
`activeBrowserEndpoint` must be `http://74.48.78.17:16666`, and
`deprecatedEndpoint` must be `null`.
- `state: "historical"` means the report is retained only for evidence
provenance. It may name a deprecated endpoint such as
`http://74.48.78.17:6667`, but it must stay blocked/non-green and cannot be
consumed as active acceptance evidence.
- Active reports may preserve a legacy public endpoint only inside an explicit
`runtimeSmoke.legacyPublicEndpoint` object with `status: "deprecated"` and
`activeGreenEligible: false`.
- Active reports must not present `:6666` or `:6667` as a current public DEV
endpoint in endpoint, route, health, ingress, API, frontend, or browser
evidence. Internal k3s service/listen ports may still be `6667` when the
surrounding field names them as cluster-local service ports rather than
public endpoints.
- M3 DEV-LIVE remains narrower than report freshness: it requires
`res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1` in real DEV
plus operation, audit, and evidence identifiers. SOURCE, LOCAL, DRY-RUN,
fixture, and historical report evidence are support/diagnostics only.
- M5 DEV-LIVE cannot be inferred from public entrypoint reachability. Reports
must keep EDGE/ROUTE live, DB live/degraded, M3 hardware trusted loop,
M4 agent loop, and artifact/desired-state source status as separate layers.
If the only read-only evidence is `16666/16667` reachability, M5 must remain
blocked/non-green.
- Gate/report aggregators must cross-check DB, M3, M4, and M5 acceptance
against the corresponding source reports before showing `DEV-LIVE` or green
status. Frontend/browser revision facts, public route reachability, source
manifests, local smoke, dry-run output, and fixtures are non-promoting
support evidence for those layers.
## Files
- `/tmp/hwlab-dev-gate/dev-gate-report.example.json`: machine-readable example.
- `/tmp/hwlab-dev-gate/dev-deploy-report.json`: DEV deploy apply/preflight result.
- `scripts/validate-dev-gate-report.mjs`: local validator for the report shape.
- `scripts/report-lifecycle.mjs`: lightweight lifecycle helper for validating
one report or marking a replaced report historical/deprecated after endpoint
changes.
## Required Fields
Every report must include:
- `$schema`
- `$id`
- `reportVersion`
- `issue`
- `taskId`
- `commitId`
- `acceptanceLevel`
- `devOnly`
- `prodDisabled`
- `reportLifecycle`
- `sourceContract`
- `validationCommands`
- `localSmoke`
- `dryRun`
- `devPreconditions`
- `blockers`
## Field Rules
- `issue` is fixed to `pikasTech/HWLAB#31`.
- `devOnly` must be `true`.
- `prodDisabled` must be `true`.
- `commitId` must be a git SHA string.
- `taskId` and `acceptanceLevel` must be stable slugs, not free-form prose.
- `validationCommands` must record the exact commands used to validate the
report contract.
- `sourceContract.documents` should point at the frozen docs that define the
gate contract.
- `localSmoke`, `dryRun`, and `devPreconditions` should each summarize their
own state with a status, command list, evidence list, and short summary.
- `blockers` should list the remaining open blockers as machine-readable
objects.
- DB gate extensions may add redacted `db`, `cloudApiDb`, or check evidence
objects. These must include only env names, presence/missing status, Secret
reference names, and redacted readiness layers such as `configReady`,
`envInjected`, `connectionAttempted`, `connectionResult`, and
`liveConnected`. They must not include connection strings, passwords, tokens,
DB hostnames from the secret URL, or fixture output presented as live DB
evidence.
- DEV deploy apply reports must include
`devDeployApply.templateJobReplacementPolicy` and
`devDeployApply.templateJobReplacements`. These fields document the
DEV-only suspended template Job replacement allowlist, plus each planned or
executed replacement with namespace, Job name, old image, new image, and
result. The allowlist is limited to `hwlab-agent-worker-template` and
`hwlab-cli-template` in `hwlab-dev`; it must not generalize to ordinary Jobs
or non-Job resources.
## Validation
Run:
```sh
node --check scripts/validate-dev-gate-report.mjs
node scripts/validate-dev-gate-report.mjs
```
The validator scans `/tmp/hwlab-dev-gate/*.json` by default. It only checks the
contract shape and the frozen report metadata; it does not run any DEV or PROD
deployment.
For M5 aggregator reports, the validator also verifies non-promotion
boundaries by reading the declared source report paths. DB acceptance must come
from redacted live DB readiness (`ready=true`, `connected=true`, and
`liveDbEvidence=true`); M3 must come from a real live operation with operation,
trace, audit, and evidence identifiers; M4 must come from the live preflight;
and M5 must remain blocked until DB, M3, M4, and the M5 live source report
each pass their own source checks. Frontend route, source, dry-run, and
fixture evidence may remain in the report, but it cannot promote those layers
to DEV-LIVE acceptance.
## Invalidate/Rebuild Workflow
When the public DEV endpoint mapping changes, do not rewrite historical
evidence strings. Preserve the old facts and mark any report that can no longer
represent the active gate as historical:
```sh
node --check scripts/report-lifecycle.mjs
node scripts/report-lifecycle.mjs invalidate /tmp/hwlab-dev-gate/<old-report>.json \
--deprecated-endpoint http://74.48.78.17:6667 \
--reason "Public DEV endpoint moved to frontend :16666 and API/edge :16667" \
--out /tmp/hwlab-dev-gate/historical/<old-report>-legacy-6667.json
node scripts/validate-dev-gate-report.mjs /tmp/hwlab-dev-gate/historical/<old-report>-legacy-6667.json
```
Then regenerate the active report through its owning script so the active file
uses `http://74.48.78.17:16666` for browser/frontend evidence and
`http://74.48.78.17:16667` for API/edge/live evidence. Keep PR notes explicit:
which legacy reports were moved or marked historical, which active reports were
regenerated, and which current reports still need real DEV reruns.
-78
View File
@@ -1,78 +0,0 @@
# DEV M4 Agent Loop
This document records the DEV-only M4 agent loop smoke for
`pikasTech/HWLAB#37`.
## Scope
- 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:16667`.
- Avoid secret reads, PROD access, long-running agent tasks, and direct gateway
access.
## Local Checks
Run the source-only smoke first:
```sh
node scripts/m4-agent-loop-smoke.mjs
```
That smoke stays local and checks the runtime skeleton, workspace isolation,
and explicit skills commit handling.
Run the bounded M4 dry-run before live preflight:
```sh
node scripts/dev-m4-agent-loop-smoke.mjs --dry-run
```
The dry-run uses only temporary local state. It records manager, worker,
workspace, skills commit, trace, evidence, and cleanup evidence as `DRY-RUN`;
it is not `DEV-LIVE`.
## Live DEV Preflight
Run the live preflight only if the DEV route is reachable and the operator has
authorized a short read-only window:
```sh
node scripts/dev-m4-agent-loop-smoke.mjs --live --confirm-dev --confirmed-non-production
```
The live path must only observe existing DEV state. It must not read tokens or
secrets, must not try to run a real agent workload, and must stop if the M3
runtime preconditions are not ready.
On D601, the live preflight also records native k3s evidence with the explicit
kubeconfig and namespace:
```sh
KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n hwlab-dev get pods,svc,deploy,job,cm -o wide
```
Worker createability is checked with server-side dry-run admission from the
existing `hwlab-agent-worker-template`. The generated Job stays suspended and is
not persisted:
```sh
KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n hwlab-dev create -f - --dry-run=server -o json
```
The smoke may check Secret RBAC with `kubectl auth can-i`, but it must not read
Secret resources, kubeconfig contents, or token values.
Any hardware assistance from M4 must go through the cloud API hardware surface
and the patch-panel trusted path for `DO1 -> patch-panel -> DI1`. The agent
must not connect directly to box or gateway simulators.
## Expected Evidence
- `agent-mgr` creates a scoped worker session.
- The worker workspace is isolated per session.
- The skills artifact is tied to an explicit commit.
- Trace, evidence, and cleanup records stay linked.
- If live DEV is blocked, the report must say why and keep the blocker class
explicit.
-109
View File
@@ -1,109 +0,0 @@
# M0 Contract Audit
This audit independently reviews whether the L0 skeleton is enough for M0
contract work under the issue constraints supplied for pikasTech/HWLAB#19 and
the referenced #7/#11/#12/#16 guardrails.
Applied constraints:
- 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.
- This audit does not modify L1-L6 service implementation directories and does
not create or claim the L5 deploy manifest.
## Audit Result
Status: conditionally passes M0 after this audit patch.
The repository already contains the L0 contract skeleton needed by parallel
MVP work:
- Root README freezes MVP scope, DEV endpoint, service IDs, and repository
layout.
- `internal/protocol/index.mjs` centralizes DEV endpoint, frozen service IDs,
table names, JSON-RPC version, and HWLAB error codes.
- `protocol/*.md` documents JSON-RPC envelopes, error codes, audit fields,
capability model, topology constraints, and the sequence-level MVP flow.
- `protocol/schemas/*.json` names the key protocol records and uses
draft-2020-12 JSON Schema shape files.
- `deploy/deploy.schema.json` names the deploy manifest fields and reuses the
frozen service ID list.
- `scripts/validate-contract.mjs` already checks protocol constants against
the common and deploy schemas.
This patch adds M0 examples under `protocol/examples/m0-contract/` and a
lightweight executable check in `scripts/validate-m0-contract.mjs` so the audit
is not document-only.
## Coverage Matrix
| Contract area | Current L0 source | Added M0 sample/check | Result |
| --- | --- | --- | --- |
| Frozen service IDs | `README.md`, `internal/protocol/index.mjs`, `protocol/schemas/common.json`, `deploy/deploy.schema.json` | `service-ids.json`, deploy sample, exact list comparison | Covered |
| JSON-RPC request/response | `protocol/json-rpc.md`, `json-rpc-envelope.schema.json`, runtime validators | `json-rpc-request.json`, `json-rpc-response.json` | Covered |
| Error envelope | `protocol/errors.md`, runtime `ERROR_CODES` | `json-rpc-error.json`, reserved code and stable `error.data` fields | Covered |
| Audit fields | `protocol/audit.md`, `audit-event.schema.json` | `audit-event.json`, required field and ID checks | Covered |
| Capability and topology | `protocol/capabilities.md`, `protocol/topology.md`, related schemas | `capability-topology.json`, cross-reference checks | Covered for M0 |
| Deploy schema fields | `deploy/deploy.schema.json`, `deploy/README.md` | `deploy-manifest.dev.json`, DEV-only example checks | Covered without L5 manifest changes |
## Rework Risk Register
Blocker: persisted schema naming drift before L1/L4/L6 integration.
`internal/db/migrations/0001_cloud_core_skeleton.sql` uses placeholder columns
such as `request_id`, `actor`, `source`, `operation`, `result`, `operation_type`,
and `evidence_type`, while the protocol schemas use `auditId`, `traceId`,
`actorType`, `serviceId`, `action`, `outcome`, `capabilityId`, and `kind`.
Before services persist real records, L1 must either align the migration with
the protocol names or provide an explicit mapping layer that is tested.
Blocker: schema files are parseable but not fully enforced at runtime.
The existing validators and the new M0 check intentionally avoid heavyweight
dependencies and do not evaluate all JSON Schema references. L1-L6 service
entry points need a shared validator such as Ajv or a generated equivalent
before accepting untrusted API, gateway, or agent payloads.
Blocker: topology constraints are partly prose-only.
M0 can verify that examples cross-reference known resources, capabilities, and
sessions. M1-M3 need a real topology validator for cycle detection, active
resource-group exclusivity, patch-panel override behavior, and gateway/box
ownership.
Blocker: deploy schema allows future `prod` profile shape.
That is acceptable for L0 compatibility, but L5 must keep MVP execution DEV-only
and reject any real PROD deploy path until a later milestone explicitly changes
the acceptance target.
Enhancement: RPC method catalog is not yet complete.
M0 freezes envelope shape, method naming, and representative
`hardware.operation.request`. Later milestones should add a method registry with
params/result schemas for project, gateway, patch-panel, worker, evidence, and
cleanup flows.
Enhancement: capability constraints are generic JSON objects.
This keeps M0 flexible, but hardware-facing work should add typed constraint
profiles for common operations such as voltage ranges, serial settings,
firmware flashing, and measurement tolerances.
Enhancement: evidence integrity is structural only.
The sample checks SHA-256 format but does not hash referenced artifacts. M4/M5
should verify artifact existence, size, content hash, and retention policy.
Enhancement: service ID drift checks are duplicated.
Current validation compares runtime constants with schema enums. A later cleanup
could generate schema enums and docs from one registry.
## Validation
Run:
```sh
npm run check
node --check scripts/validate-m0-contract.mjs
node scripts/validate-m0-contract.mjs
```
The M0 script parses all JSON files in `protocol/examples/m0-contract/`, checks
the audit Markdown headings, and verifies the representative cross-document
invariants needed for M0.
-82
View File
@@ -1,82 +0,0 @@
# M1 SOURCE/LOCAL Contract Smoke
The M1 local smoke is a fast contract check for the current HWLAB MVP
runtime. It runs only on the local machine, uses short-lived localhost
processes, and does not deploy or call the frozen DEV endpoint. It is
SOURCE/LOCAL evidence only, not DEV-LIVE evidence.
Run it from the repository root:
```sh
node scripts/m1-contract-smoke.mjs
```
The equivalent npm entry point is:
```sh
npm run m1:smoke
```
## What It Checks
- Starts `hwlab-cloud-api` on `127.0.0.1` with an ephemeral port and checks
`/health`, `/live`, `GET /v1`, and `POST /rpc`.
- Verifies the cloud-api runtime returns degraded `system.health` when DB
persistence is not connected, describes the REST and JSON-RPC adapter
surface, registers a gateway/box/capability, and records an accepted
`hardware.operation.request` in process-local memory.
- Starts `hwlab-gateway-simu`, `hwlab-box-simu`, and `hwlab-patch-panel` on
ephemeral localhost ports.
- Checks simulator health and status payloads, confirms cross-device
propagation is `patch-panel-only`, writes a local box port value, and routes a
signal through the patch panel fixture.
- Checks `hwlab-agent-mgr` local health and sample manager lifecycle JSON
(`health`, `create`, `status`, `cleanup`) in a temporary state directory.
- Parses `fixtures/mvp/runtime.json` through the CLI dry-run path and verifies
the dry-run output names the MVP route, closed loops, evidence fixture, and
the no-DEV/PROD-change disclaimer.
## Boundary
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:16667`;
- run browser e2e;
- read secrets, tokens, kubeconfig, tunnel credentials, or deploy manifests;
- validate real gateway, router, frp, edge proxy, agent, worker, or hardware
behavior;
- replace the L5 deploy manifest work.
The check is scoped to the local M1 contract boundary: existing cloud-api,
patch-panel, simulator, agent-mgr, Code Agent chat schema, and CLI dry-run
runtime paths can be started or parsed and still agree on the frozen service
IDs, DEV environment, JSON-RPC/REST surface, DB degradation contract, local
manager lifecycle shape, and patch-panel-only topology assumptions.
The Code Agent chat check intentionally exercises only SOURCE/LOCAL contract
shape. User workbench backend routing may be present in the codebase, but a
real assistant reply and provider-backed completion must be validated by separate
DEV-LIVE work.
## Follow-On DEV e2e
A later real DEV e2e should run against the deployed DEV route, exercise the
actual cloud-web/cloud-api, gateway/router/tunnel path, hardware trusted closed
loop, agent automation closed loop, evidence persistence, and cleanup behavior.
That later test should produce deployment/evidence artifacts and must remain
separate from this local smoke harness.
## L2 Runtime Smoke
The L2 simulator runtime has a separate local check:
```sh
npm run l2:smoke
```
It starts two `hwlab-gateway-simu` and two `hwlab-box-simu` processes on
ephemeral localhost ports. It proves simulator identity, AI/AO/DI/DO/FREQ
state operations, gateway register/heartbeat/capability/invoke forwarding,
error codes, audit/evidence shapes, and the patch-panel-only propagation
boundary. It does not call DEV or PROD.
-142
View File
@@ -1,142 +0,0 @@
# M3 Hardware Trusted Loop Local Contract
This contract smoke proves the local M3 wiring path for:
```text
box-simu-1 DO1 -> box-simu-2 DI1
```
The fixture is `fixtures/mvp/m3-hardware-loop/topology.json`. It contains two
`hwlab-box-simu` resources, two `hwlab-gateway-simu` sessions, and one
`hwlab-patch-panel` status object. The active wiring config has one exclusive
connection from `res_boxsimu_1:DO1` to `res_boxsimu_2:DI1`.
Run the smoke locally:
```sh
node scripts/m3-hardware-loop-smoke.mjs
```
## What It Checks
- DEV-only topology with two boxes, two gateways, and one active patch panel.
- Patch-panel-only propagation; box local loopback is not accepted as a
cross-device substitute.
- Direct local call into the existing patch-panel model routes
`box-simu-1 DO1` to `box-simu-2 DI1`.
- An unwired local signal does not cross devices.
- The expected audit event includes the L0 audit fields:
`auditId`, `traceId`, `actorType`, `actorId`, `action`, `targetType`,
`targetId`, `serviceId`, `environment`, and `occurredAt`, plus project,
gateway session, operation, outcome, and metadata fields.
## Boundary
This is a local contract smoke only. It does not deploy DEV or PROD services,
does not connect to real hardware, does not read secrets or tokens, and does
not write `audit_events` rows to a database. The audit event in the fixture is
an expected record shape for the future real flow.
The later real DEV M3 path must replace the in-process direct call with live
service boundaries: cloud request validation, gateway session ownership,
patch-panel state application, real or simulator box observation, persisted
audit events, and evidence records. That future work must preserve the same
wiring contract and must keep routing decisions under `hwlab-patch-panel`
ownership instead of mutating another box directly.
## L2 Local Runtime Smoke
Issue 53 adds a runnable localhost-only L2 simulator contract:
```sh
npm run l2:smoke
```
The smoke starts two `hwlab-box-simu` instances (`box-a`, `box-b`) and two
`hwlab-gateway-simu` instances (`gateway-a`, `gateway-b`) on ephemeral
localhost ports. It verifies:
- box ports for `AI1`, `AO1`, `DI1`, `DO1`, and `FREQ1`;
- internal port API writes for patch-panel-owned delivery;
- gateway register, heartbeat, capability report, and invoke forwarding;
- multi-instance identity separation for `box-a`/`box-b` and
`gateway-a`/`gateway-b`;
- HWLAB JSON-RPC error codes for missing gateway registration and unavailable
capabilities;
- returned audit and evidence object shapes.
This smoke is still not a DEV deploy or PROD deploy. It proves the minimum
runtime surface that later M3/M5 live checks can call. Cross-device propagation
is not implemented as box-simu loopback; the only accepted cross-device owner
remains `hwlab-patch-panel`, which calls the box internal port API.
## DEV Runtime Smoke
Use the no-write plan first:
```sh
node scripts/dev-m3-hardware-loop-smoke.mjs --dry-run
```
The dry-run plan writes `/tmp/hwlab-dev-gate/dev-m3-hardware-loop.json` by
default, records `dryRunPlan.evidenceLevel: "DRY-RUN"`, lists the live write
preconditions, enumerates the endpoints that a later live run would call, and
keeps `liveOperation.status: "not_run"`. It does not call DEV endpoints, does
not send `/ports/write` or `/signals/route`, and cannot be promoted to
`DEV-LIVE`.
Use this command only for the approved DEV simulator runtime window:
```sh
node scripts/dev-m3-hardware-loop-smoke.mjs --live --confirm-dev --expect-non-prod
```
The legacy `--confirmed-non-production` flag is accepted as compatibility, but
new handoffs should use `--expect-non-prod`. Missing or incomplete live
authorization stays on the source/read-only plan path, and `--dry-run` combined
with `--live` remains no-write.
The live smoke writes `/tmp/hwlab-dev-gate/dev-m3-hardware-loop.json`. It first
checks 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.
If DEV ingress is reachable, the script requires explicit direct DEV simulator
targets through these environment variables:
```text
HWLAB_DEV_BOX_SIMU_1_URL
HWLAB_DEV_BOX_SIMU_2_URL
HWLAB_DEV_GATEWAY_SIMU_1_URL
HWLAB_DEV_GATEWAY_SIMU_2_URL
HWLAB_DEV_PATCH_PANEL_URL
```
Those targets must be two distinct HWLAB DEV simulator services for each
box/gateway role, plus one callable HWLAB DEV patch panel, not UniDesk
substitutes. Missing direct targets are classified as `target_missing`,
duplicated box or gateway identities as `identity_not_distinct`, and missing
`res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1` wiring as
`patch_panel_wiring_missing`. Each of those stop conditions keeps
`liveOperation.status` at `not_run` and prevents the DEV write/read smoke from
starting. The script then checks two box simulators, two gateway simulators,
active patch-panel wiring for
`res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1`, a live direct
call that reads `DI1=true`, and returned operation, trace, audit, and evidence
identifiers. Fixture-backed local M3 output is never accepted as live DEV
evidence.
## Read-Only Continuation Evidence
When DEV ingress is blocked, continuation work may still record read-only
evidence. The smoke report includes a static comparison of
`deploy/k8s/base/workloads.yaml` against the M3 requirement for two
`hwlab-box-simu` instances and two `hwlab-gateway-simu` instances. This is not
live runtime proof. The checked-in DEV manifests are source-ready only when
`node scripts/validate-dev-m3-cardinality.mjs` passes: two `hwlab-box-simu`
replicas with `boxsimu_1,boxsimu_2`, two `hwlab-gateway-simu` replicas with
`res_boxsimu_1,res_boxsimu_2`, and one `hwlab-patch-panel`. If the live runtime
still lacks the required simulator cardinality, the fix is a separate
authorized DEV deploy or runtime task, not a mutation inside the M3 evidence
collection task.
-72
View File
@@ -1,72 +0,0 @@
# M4 Agent Automation Loop Local Contract Smoke
Run the local M4 smoke from the repository root:
```sh
node scripts/m4-agent-loop-smoke.mjs
```
This check stays local. It uses the `internal/agent` runtime skeleton and a
repo fixture to verify:
- lifecycle coverage for `create`, `start`, `trace`, `finish`, and `cleanup`;
- manager `create/status/trace/evidence/cleanup` contract behavior through the
local file-system runtime;
- worker `dry-run` task claim, trace write, evidence write, and temporary
workspace cleanup;
- workspace isolation per agent session;
- explicit skills `commitId` and `version` wiring;
- evidence record fields, URI shape, and SHA-256 digest;
- the fixture evidence note that marks the run as local-only.
The local CLI contract is JSON-only and short-lived:
```sh
STATE_DIR="$(mktemp -d)"
node cmd/hwlab-agent-mgr/main.mjs create --state-dir "$STATE_DIR" \
--agent-session-id agt_local_m4 --project-id prj_local_m4 \
--goal "verify local agent loop" --prompt "dry-run" \
--skill-commit-id 6509a35 --skill-version v1
node cmd/hwlab-agent-worker/main.mjs dry-run --state-dir "$STATE_DIR" \
--agent-session-id agt_local_m4 \
--skill-commit-id 6509a35 --skill-version v1
node cmd/hwlab-agent-mgr/main.mjs status --state-dir "$STATE_DIR" \
--agent-session-id agt_local_m4
node cmd/hwlab-agent-mgr/main.mjs trace --state-dir "$STATE_DIR" \
--agent-session-id agt_local_m4
node cmd/hwlab-agent-mgr/main.mjs evidence --state-dir "$STATE_DIR" \
--agent-session-id agt_local_m4
node cmd/hwlab-agent-mgr/main.mjs cleanup --state-dir "$STATE_DIR" \
--agent-session-id agt_local_m4
```
If either skills `commitId` or `version` is omitted, health and evidence are
reported as `degraded`; no fallback commit or external skill source is inferred.
## Real DEV Preconditions
A real DEV M4 run is separate from this smoke. It would need a live DEV
environment, a seeded `prj_*` project, the `hwlab-agent-mgr`,
`hwlab-agent-worker`, and `hwlab-agent-skills` services, and a stable
`hwlab-agent-skills` artifact with an explicit `commitId`.
That live path must not read tokens or secrets from the runner. Do not inspect
`GH_TOKEN`, `GITHUB_TOKEN`, kubeconfig material, tunnel credentials, or any
other secret-bearing source as part of this smoke. If a live M4 path cannot run
without those reads, the blocker is safety, not contract shape.
## Failure Classification
- `contract_blocker`: fixture, lifecycle, or field shape mismatch.
- `environment_blocker`: DEV-only boundary or endpoint assumptions are wrong.
- `agent_blocker`: workspace isolation, cleanup, or evidence wiring fails.
- `observability_blocker`: a live artifact cannot be tied to service or
`commitId` identity.
- `safety_blocker`: any secret read, real deployment, or long-running agent
task.
## What This Is Not
This does not deploy, does not call production, and does not run a real agent
job. It only checks the local runtime skeleton contract and its fixture-backed
evidence note.
-116
View File
@@ -1,116 +0,0 @@
# M5 MVP E2E Dry-Run Orchestration
M5 is the static orchestration gate before the first real DEV MVP e2e run. It
does not deploy, does not call DEV, does not run browser e2e, and does not read
secrets. The source contract gate is:
```sh
node scripts/m5-mvp-e2e-dry-run.mjs
```
The script reads the frozen protocol contracts, the DEV acceptance checklist,
`fixtures/mvp/runtime.json`, and `fixtures/mvp/m5-e2e/dry-run-plan.json`. It
validates the dependency graph and checks that each step has resolvable inputs
and outputs.
The L6 external acceptance CLI wraps the same report and dry-run plan:
```sh
node tools/hwlab-cli/bin/hwlab-cli.mjs test e2e --env dev --mvp
```
Cloud Web #59 adds a separate read-only diagnostics contract:
```sh
node web/hwlab-cloud-web/scripts/check.mjs
```
This contract is source-only. It verifies the public frontend/API endpoint
split, the read-only JSON-RPC calls used by Cloud Web, the visible topology,
route, health, and M3 evidence summary, and the rule that edge-only
observations cannot be displayed as M3 `DEV-LIVE`.
This command defaults to a JSON dry-run plan. `--dry-run` is accepted for
backward compatibility, but it is no longer required for safety. The output
must identify the M0-M5 report source, artifact and DEV health contract counts,
two gateway sessions, two box resources, patch-panel status, agent and worker
session IDs, evidence records, open blockers, and the statement that no
DEV/PROD changes were made.
## Dry-Run Flow
| Order | Step | Purpose | Required Inputs | Required Outputs |
| --- | --- | --- | --- | --- |
| 1 | DEV health | Confirm the frozen DEV endpoint and recorded edge/frp/D601/cloud health contracts. | DEV endpoint, ingress, edge route, frp, router, cloud API/web health records | Route, tunnel, namespace, cloud service identities |
| 2 | Gateway/box status | Confirm gateway, simulator, resources, and capabilities are present. | Gateway sessions, box resources, capabilities | Gateway session, resource IDs, capability IDs |
| 3 | Wiring | Confirm the active wiring config is patch-panel owned. | Wiring config, patch-panel status | Wiring config ID, patch-panel status ID |
| 4 | Direct hardware call | Validate the direct JSON-RPC hardware operation envelope and field flow. | RPC request/response, resource, capability, patch-panel status | Operation ID, trace ID |
| 5 | Audit | Confirm mutating setup and direct operation audit records exist. | Project, gateway, wiring, operation audit records | Direct operation audit ID |
| 6 | Agent session | Confirm agent manager, worker, and skills contracts are linked. | Agent/worker sessions, agent health records | Agent session ID, worker session ID |
| 7 | Agent hardware call | Validate the agent worker JSON-RPC hardware operation envelope and field flow. | RPC request/response, agent, worker, resource, capability, patch-panel status | Operation ID, trace ID |
| 8 | Evidence | Confirm both hardware operations emit trace and evidence records. | Trace events, evidence records | Evidence IDs |
| 9 | Cleanup | Confirm worker and gateway transient cleanup are recorded. | Cleanup records, cleanup audit | Cleanup IDs |
## M0-M4 Dependency Graph
M5 closes over the earlier MVP contracts as contract-only prerequisites:
| Source | Provides | Consumed By M5 |
| --- | --- | --- |
| M0 contract audit | Frozen service IDs, protocol schemas, MVP e2e sequence contract | DEV health, hardware operation envelopes, evidence contract |
| M1 local smoke | Static parse boundary and dry-run safety posture | DEV health and cleanup safety checks |
| M2 cloud core | Project record, JSON-RPC envelope, audit surface | Audit, direct hardware call, agent hardware call |
| M3 hardware loop | Gateway session, box resources/capabilities, wiring config, patch-panel status | Gateway/box status, wiring, direct hardware call, agent hardware call |
| M4 agent runtime | Agent session, worker session, trace events, evidence, cleanup | Agent session, agent hardware call, evidence, cleanup |
The graph must remain acyclic. Each M5 step may only depend on earlier steps
except the agent hardware call, which also depends on the already-established
wiring step.
## Blocker Classes
M5 keeps the blocker classes from the DEV acceptance matrix:
| Class | Meaning |
| --- | --- |
| `contract_blocker` | Static contract, schema, checklist, or documentation cannot be parsed or contradicts frozen names. |
| `environment_blocker` | DEV endpoint, environment, namespace, or PROD boundary is wrong. |
| `network_blocker` | Master edge, frp, D601 route, or public DEV ingress cannot be observed or routes incorrectly. |
| `runtime_blocker` | HWLAB cloud, router, gateway, simulator, box simulator, or patch-panel runtime contract fails. |
| `agent_blocker` | Agent manager, worker, skills, trace, audit, or cleanup contract fails. |
| `observability_blocker` | Artifact identity, commit, image/tag/digest, build source, deploy env, or health timestamp is missing. |
| `safety_blocker` | Any prohibited action was attempted: real deployment, PROD target, browser/heavyweight e2e, secret read, force push, or UniDesk runtime substitution. |
## Real DEV E2E Gate
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:16667`.
3. Every accepted artifact has `serviceId`, `commitId`, `image`, `tag`,
`digest` or `not_applicable` reason, `buildSource`, `deployEnv`, and
`healthTimestamp`.
4. DEV ingress, master edge proxy, frp, and D601 `hwlab-dev/hwlab-router` have
current route observations.
5. Cloud API/web, gateway, gateway simulator, box simulator, patch panel, agent
manager, worker, and skills are all observed in DEV with HWLAB service
identities.
6. Gateway and box control remain patch-panel owned; no direct box bypass path
is accepted.
7. Agent worker scope, trace, audit, evidence, and cleanup are observable and
tied to one DEV project.
8. No blocker class is open and a human has explicitly approved a real DEV
smoke.
Only after those gates are satisfied should the runner switch from dry-run to
the explicit live DEV command:
```sh
hwlab-cli test e2e --env dev --mvp --live --confirm-dev --confirmed-non-production
```
That command is intentionally not executed by M5. While
`GitHub issue/PR comments` contains open blockers, the CLI
must return `code: "BLOCKED"` with blocker evidence instead of substituting
fixture output as live DEV evidence.
-384
View File
@@ -1,384 +0,0 @@
# HWLAB Operator Runbook
This runbook is the manual acceptance guide for commanders and operators during
the first HWLAB DEV-only MVP. It defines when a phase may start, when it must
stop, how failures are classified, and which actions are prohibited.
The runbook supports M0-M5 and the DEV-only MVP path. It does not authorize a
real DEV deployment, PROD deployment, secret access, service restart, or
heavyweight e2e run by itself.
## Fixed Boundary
- Repository: `pikasTech/HWLAB`.
- MVP environment: `dev`.
- DEV frontend endpoint: `http://74.48.78.17:16666`.
- DEV API/edge endpoint: `http://74.48.78.17:16667`.
- Legacy public endpoints `:6666` and `:6667` are deprecated and are not MVP acceptance targets.
- Internal k3s service ports may still use `6667`; internal `6667` is not a public acceptance endpoint.
- 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`.
- UniDesk services may support scheduling, CI, or CD only. They are not accepted
as substitutes for HWLAB runtime services.
- Code Agent provider credentials are DEV-only runtime inputs: `OPENAI_API_KEY`
must come from Secret `hwlab-code-agent-provider/openai-api-key`, and
`HWLAB_CODE_AGENT_OPENAI_BASE_URL` must route through the DEV egress/proxy
path, not direct public `api.openai.com`.
- Cloud API DB readiness is layered as DNS, TCP, auth, and schema. `.invalid`
hosts are never desired DEV runtime targets; they are negative fixtures only.
## M3 MVP Acceptance
M3 MVP PASS is the smallest real DEV evidence chain that proves the hardware
trusted loop. It requires:
- two box simulators with different observable identities;
- two gateway simulators with different observable identities;
- one active patch-panel participant;
- the traced `res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1`
operation with trace, audit, operation, and evidence IDs;
- no box loopback substitution, no front-end direct state edit, and no
UniDesk runtime or proxy substitution.
Cloud Workbench, generic console work, artifact report generation, and
desired-state planning are support surfaces only. They may help operators, but
they do not count as M3 PASS on their own and cannot replace the loop evidence
above.
The detailed step order and misclassification bans live in
`docs/reference/m3-loop-rollout-runbook.md`; this runbook and the acceptance
matrix mirror that contract.
## Runner Issue Visibility Handoff
GitHub issue and PR threads are auxiliary context only. The runner prompt must be self-contained and must include the full task objective, background, constraints, acceptance, and validation commands.
Do not assume issue comments are readable in the runner. If a task depends on GitHub visibility, use `docs/reference/runner-issue-visibility-handoff.md` as the stable prompt contract and run `node scripts/runner-issue-visibility-preflight.mjs` before queueing the work.
The current runner class may have git transport access while GitHub REST issue and PR reads are blocked. Treat that as a prompt-handoff requirement, not a reason to omit context from the prompt.
## Hard Stop Actions
Stop the run immediately and classify the event as a safety blocker if any
operator, script, or agent attempts one of these actions:
- Perform a real DEV deployment from this runbook.
- Deploy, smoke, or mutate PROD in any form.
- Read, print, copy, or infer secrets, tokens, kubeconfig, tunnel credentials,
API keys, or private environment values.
- Restart UniDesk, Code Queue, or `backend-core`.
- Run heavyweight e2e, destructive hardware tests, load tests, or unbounded
browser automation.
- Use UniDesk backend, provider-gateway, or microservice proxy as the HWLAB
runtime instead of `hwlab-cloud-api`, `hwlab-router`, `hwlab-gateway`,
`hwlab-patch-panel`, agent services, and the other frozen HWLAB services.
- Promote SOURCE, LOCAL, DRY-RUN, or edge-only result as real DEV evidence.
- Treat Cloud Workbench polish, generic console work, artifact reports, or
desired state plans as M3 PASS evidence.
- Leave an emergency DEV runtime hotfix as the only source of truth after it
unblocks a P0 path. The follow-up must codify source manifests, contracts,
docs, and validation without rerunning the live patch.
## Evidence Log
Every phase result must be recorded in the operator log before the next phase
starts. The log may be a ticket comment, incident note, or release checklist,
but it must include:
- phase name and milestone IDs;
- command or observation used;
- commit SHA;
- environment, which must be `dev` for MVP evidence;
- endpoint, when a network observation is made;
- pass, fail, blocked, or not-applicable status;
- failure class, when failed or blocked;
- artifact identity for deployable runtime observations: `serviceId`,
`commitId`, `image`, `tag`, `digest` or `not_applicable` reason,
`buildSource`, `deployEnv`, and `healthTimestamp`;
- evidence, audit, trace, operation, agent session, worker session, gateway
session, and project IDs when the phase touches an MVP loop.
## DEV Gate Aggregator v2
Use `/tmp/hwlab-dev-gate/dev-m5-gate-aggregator-v2.json` and
`/tmp/hwlab-dev-gate/dev-m5-gate-aggregator-v2.md` as the current report-only M5
gate summary for `pikasTech/HWLAB#58`. Refresh them only from committed
fixtures:
```sh
node scripts/dev-evidence-blocker-aggregator.mjs --report /tmp/hwlab-dev-gate/report.json
node scripts/validate-dev-gate-report.mjs
```
The aggregator separates `SOURCE`, `LOCAL`, `DRY-RUN`, `DEV-LIVE`, and
`BLOCKED`. It must never promote source, local, dry-run, contract-only,
not-run, or failed-live evidence into `DEV-LIVE`.
Current unblock order:
1. Provide an approved Node 20 DEV builder base image for artifact publish.
2. Publish every frozen HWLAB service artifact and record immutable registry
digests for the selected `origin/main` commit.
3. Restore read-only D601 `hwlab-dev` k3s observability with
`KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl` or an approved
kubeconfig/maintenance bridge, without reading Secrets. Do not use a default
`docker-desktop` kubeconfig as DEV evidence; the control-plane incident is
tracked in pikasTech/unidesk#138.
4. Prove DEV `hwlab-cloud-api` DB env and health readiness with redacted values
only.
5. Repair the `:16667`/`frp`/edge/router path and rerun read-only DEV edge
health before any M3, M4, or M5 live loop.
For #164-style hotfix follow-up, treat provider and DB fixes as independent
contracts:
- Code Agent provider: source and k8s workload env must declare
`OPENAI_API_KEY` from `hwlab-code-agent-provider/openai-api-key` and
`HWLAB_CODE_AGENT_OPENAI_BASE_URL` through DEV egress/proxy. Validation may
prove Secret ref shape and key-presence evidence only; it must not print the
API key.
- DB live: source and runtime health must reject `.invalid` as a DEV target and
report DNS/TCP/auth/schema readiness separately. `liveDbEvidence=true` is
allowed only after live runtime connectivity evidence, never from fixtures or
env presence alone.
- Follow-up automation: update `deploy/deploy.json`,
`deploy/k8s/base/workloads.yaml`, source contract code, docs, and tests; do
not apply manifests, restart services, mutate PROD, or repeat the manual
hotfix from the source PR.
## Phase Gates
Run phases in order. A later phase may start only after every earlier required
exit condition is met or explicitly marked not applicable with a DEV-only
reason.
| Phase | Covers | Entry Conditions | Exit Conditions |
| --- | --- | --- | --- |
| 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: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. |
## Milestone Coverage
| Milestone | Operator Gate | Required Acceptance |
| --- | --- | --- |
| M0 contract audit | Source-only | `docs/m0-contract-audit.md`, protocol docs, schemas, deploy schema, and M0 examples agree on service IDs, JSON-RPC envelope, errors, audit fields, topology, and DEV-only deploy shape. |
| M1 local contract smoke | Local smoke | `npm run m1:smoke` or `node scripts/m1-contract-smoke.mjs` passes on localhost and confirms the local cloud-api runtime, simulator contracts, patch-panel routing, CLI dry-run boundary, and no DEV/PROD changes. |
| M2 DEV deploy/runtime smoke | Dry-run, then authorized DEV runtime smoke | Source/manifests and `docs/dev-acceptance-matrix.md` identify the DEV route through edge, `frp`, and D601 router. Real DEV observation is read-only and must not be performed without commander authorization. |
| M3 hardware trusted loop | Local smoke, then MVP e2e | `node scripts/m3-hardware-loop-smoke.mjs` proves the local contract, but M3 MVP PASS in DEV requires the live `res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1` evidence chain with distinct box/gateway identities and operation, trace, audit, and evidence IDs. |
| M4 agent automation loop | Source-only or dry-run, then MVP e2e | Agent manager, worker, skills, session lifecycle, scoped workspace, trace events, cleanup, and evidence chain are observable in fixtures or dry-run before any DEV runtime action. |
| M5 MVP e2e dry-run and acceptance | Dry-run, then MVP e2e | `npm run cli:dry-run` or equivalent names the MVP route, closed loops, evidence, and cleanup without mutation. Real acceptance is DEV-only, bounded, and requires prior DEV runtime smoke pass. |
## L6 CLI/Web Acceptance Entry
Use the L6 entry points for external manual acceptance triage. They read the
checked-in `GitHub issue/PR comments` and
`fixtures/mvp/m5-e2e/dry-run-plan.json`; they do not call UniDesk runtime and
do not claim live DEV evidence from fixtures.
Safe source and dry-run checks:
```sh
npm run l6:smoke
npm run web:m3-readonly
npm run web:check
npm run cli:dry-run
node tools/hwlab-cli/bin/hwlab-cli.mjs test e2e --env dev --mvp
```
For Cloud Web #99, `docs/cloud-web-workbench.md` is the frontend design and
acceptance contract. The browser endpoint remains public `:16666`, while
API/edge status remains public `:16667`. The default page must be the Cloud
Workbench: left activity rail/resource tree, center Agent conversation/trace,
right hardware/evidence side panel, and bottom command/input area.
Cloud Web #59 diagnostics move under the secondary diagnostics route. Keep
`diagnostics/status` and `diagnostics/gate` available for read-only
topology/route/health/evidence review, but do not use Gate or M3 Diagnostics
as the default homepage.
`npm run web:m3-readonly` remains the current safety guard until replaced by a
workbench-aware equivalent. It must keep same-origin `/v1`, read-only
`/json-rpc`, source/gate report, and blocked report boundaries; it must fail
on hardware write APIs, endpoint drift, missing `SOURCE`/`DRY-RUN`/`DEV-LIVE`
or `BLOCKED` source labels, and edge-only observations presented as M3
`DEV-LIVE`.
The default CLI MVP command is a JSON dry-run plan even when `--dry-run` is not
provided. It must include the DEV endpoint, artifact/health counts, two
gateway sessions, two box resources, the patch-panel status, agent and worker
session IDs, evidence records, and a statement that no DEV/PROD changes were
made.
The dry-run shape is support evidence only. It cannot be promoted to M3 PASS
unless the real DEV loop above is present and traceable.
The live DEV entry point is intentionally separate:
```sh
node tools/hwlab-cli/bin/hwlab-cli.mjs test e2e --env dev --mvp --live --confirm-dev --confirmed-non-production
```
When the M0-M5 gate report still has open blockers, the live command must stop
with `code: "BLOCKED"` and include the blocker evidence. It must not use
fixture data, UniDesk services, PROD, heavy e2e, restarts, or secret reads to
produce a green result.
## Phase Procedures
### Source-Only Procedure
Use this gate for contract review, static checks, fixture checks, and manifest
review. It is the default state before any runtime action is authorized.
Entry:
- `git fetch origin main` has completed.
- The working tree is based on latest `origin/main`.
- The change or review does not require secrets, kube access, tunnel access, or
a deployment command.
- The operator has identified the relevant contract source:
`README.md`, `protocol/`, `deploy/deploy.schema.json`,
`docs/dev-acceptance-matrix.md`, M0/M1/M3 docs, or MVP fixtures.
Exit:
- 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.
- Any unresolved issue is logged under one of the failure classes below.
### Local Smoke Procedure
Use this gate for localhost skeleton checks and in-process model checks.
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:16667`, `:16666`, kube, `frp`, edge
runtime, or real hardware.
Exit:
- Local services start on loopback or ephemeral ports and shut down cleanly.
- Patch-panel-only propagation is preserved.
- CLI output states dry-run or local boundary when applicable.
- Audit and evidence expectations are shape-checked but not claimed as
persisted DEV records.
### Dry-Run Procedure
Use this gate for CLI, web, runtime plan, agent loop, and MVP e2e readiness
without mutation.
Entry:
- Source-only and required local smoke gates passed.
- The dry-run command has an explicit dry-run flag or documented fixture input.
- The operator has confirmed the command cannot deploy, restart services, read
secrets, write to real hardware, or mutate DEV/PROD state.
Exit:
- Output identifies the DEV endpoint and MVP route.
- Output includes both required loops: hardware trusted closed loop and agent
automation closed loop.
- Output includes expected trace, audit, evidence, and cleanup records.
- Output explicitly states that no DEV/PROD changes were made.
### DEV Runtime Smoke Procedure
Use this gate only after commander authorization for read-only DEV observation.
This runbook does not grant that authorization.
Entry:
- M0, M1, and required dry-runs passed.
- Commander recorded an authorized DEV-only, read-only smoke window.
- The operator has the expected artifact list and service IDs.
- The planned observations require no secret reads and no restart.
- Stop criteria and rollback owner are recorded.
Exit:
- DEV endpoint responds through the HWLAB route, not a UniDesk substitute.
- Edge, `frp`, D601 router, cloud API/web, gateway or simulator,
patch-panel, agent manager, agent worker, agent skills, and CLI observations
match `docs/dev-acceptance-matrix.md` where applicable.
- Every observed runtime component identifies `dev` and a HWLAB service ID.
- Artifact identity is traceable or a `not_applicable` reason is recorded.
- Any timeout, stale health, wrong namespace, wrong endpoint, or missing
identity is classified before further action.
### MVP E2E Procedure
Use this gate only for a bounded DEV-only MVP acceptance run after DEV runtime
smoke has passed. It must remain much narrower than a heavyweight e2e suite.
Entry:
- DEV runtime smoke passed in the same acceptance window or was explicitly
accepted by the commander as still current.
- The MVP scenario is named and scoped to one project, one gateway path, one
patch-panel wiring config, one agent session, and one worker session unless
the commander records a narrower or equivalent scope.
- Expected hardware operation, cleanup action, evidence target, and stop
criteria are recorded.
- No PROD, secret read, restart, or UniDesk runtime substitute is involved.
Exit:
- Project is created or selected.
- Gateway session starts for `hwlab-gateway` or `hwlab-gateway-simu`.
- Box resources and capabilities are registered.
- Patch-panel wiring config passes topology validation and owns routing.
- Agent and worker sessions start with scoped identity.
- Hardware operation is requested through the HWLAB JSON-RPC path.
- Trace events cover accepted, dispatched, executed, completed, evidence, and
cleanup milestones.
- Audit events cover mutating steps and final outcome.
- Evidence record is persisted or, for a dry-run, fixture-bound and clearly
marked as not persisted.
- Cleanup completes and no worker, gateway, patch, project, or hardware state
leak remains.
## Failure Classes
Classify failures before retrying. If more than one class applies, choose the
earliest blocker in the run path and mention secondary symptoms in the log.
| Failure Class | Typical Symptoms | Immediate Operator Action |
| --- | --- | --- |
| Contract failure | Schema parse failure, JSON-RPC envelope mismatch, service ID drift, endpoint drift, topology rule mismatch, audit field drift, unsupported PROD target in an MVP artifact. | Stop phase; link the failing file or command; keep investigation source-only until contract drift is fixed. |
| Image/version failure | Missing image, mutable tag, missing digest, health reports wrong commit, skill bundle has no commit ID, web or CLI artifact cannot be tied to source. | Stop runtime promotion; require artifact rebuild or provenance fix; do not substitute another service. |
| k3s/frp/edge failure | DEV ingress timeout, wrong port, edge route missing, `frp` tunnel down, D601 router namespace mismatch, stale route, non-HWLAB response. | Stop DEV runtime smoke; record route segment and timestamp; do not restart UniDesk, Code Queue, `backend-core`, or unrelated infrastructure. |
| Agent failure | Agent manager unavailable, worker session unscoped, missing agent/worker IDs, unsafe mutation, skill mismatch, worker cleanup leak, missing trace event. | Stop agent loop or MVP e2e; preserve logs and IDs; do not rerun with broader permissions or secret access. |
| Hardware loop failure | Gateway unavailable, box resource missing, capability mismatch, direct box mutation, patch-panel bypass, topology conflict, DO/DI observation mismatch. | Stop hardware loop; leave hardware state unchanged when possible; require patch-panel/topology review before retry. |
| Evidence/audit failure | Missing audit event, missing evidence record, trace/audit/evidence IDs not linked, wrong environment, missing operation ID, artifact hash mismatch, cleanup not evidenced. | Stop acceptance; do not claim MVP pass; repair evidence chain or rerun only the smallest authorized DEV-only scope. |
## DEV-Only MVP Acceptance Path
The commander may call MVP accepted only when all items below are true:
1. M0 source-only contract gate passed.
2. M1 local smoke gate passed.
3. M2 dry-run readiness passed and any real DEV runtime smoke was explicitly
authorized, read-only, and passed.
4. M3 hardware trusted loop passed locally and, when authorized, through the
DEV HWLAB route with patch-panel ownership.
5. M4 agent automation loop passed dry-run or source contract checks and, when
authorized, through scoped DEV agent and worker sessions.
6. M5 dry-run passed, then the bounded DEV-only MVP e2e completed with trace,
audit, evidence, and cleanup records.
7. The evidence log contains no unclassified failure, safety blocker, PROD
action, secret read, unauthorized restart, heavyweight e2e, or UniDesk
runtime substitution.
If any item is missing, the result is blocked or partially passed, not MVP
accepted.
-85
View File
@@ -1,85 +0,0 @@
# Device Pod CLI MVP 计划
本文描述 `device-pod-cli` 第一阶段实现计划。它保留为历史 CLI MVP 闭环记录;正式 v0.2 多用户接入规格以 [../reference/spec-device-pod.md](../reference/spec-device-pod.md) 为准。本文中的本地 `.device-pod/` profile 只代表早期 MVP 输入,不适用于正式 profile authority、授权或路由决策。
## 目标
`device-pod-cli` 是给 HWLAB code agent 使用的独立硬件能力 CLI,不并入 `hwlab-cli`,也不继承 `hwlab-cli` 的广泛管理权限。第一版目标是先不实现真正的 `device-pod-server`,而是把 `device-pod` 当作 profile 驱动的抽象能力单元,通过以下路径跑通最小真实闭环:
```text
code agent -> device-pod-cli -> hwlab cloud-api/gateway -> device-host-cli -> debug probe / serial / WiFi / vendor protocol -> target
```
gateway 保持单纯 cmd 转发;硬件协议、串口、下载器和厂商工具复杂度隔离在用户 PC 上的 `device-host-cli` 后面。`device-pod-cli` 只暴露 workspace、debug-probe、io-probe 的受控语义能力,不提供泛化远程 shell。
## Profile 来源
CLI 每次执行都从 HWLAB code agent workspace 的 `.device-pod/` 目录读取 profile。推荐文件名为 `.device-pod/<devicePodId>.json`;后续可以兼容 YAML,但 MVP 优先使用 JSON,方便 schema 校验和 trace 记录。
在 CLI MVP 阶段,profile 是本地执行输入,不做中心注册。CLI 输出必须包含 `profilePath``profileHash``devicePodId``targetId`,便于确认每次操作实际使用的是哪个 profile。profile 中只允许描述 route、受控 workspace root、debug-probe 能力、io-probe 能力和 host CLI 能力;不得写入 Git key、云端 token、kubeconfig、数据库 URL 或长期 secret。正式 v0.2 接入后,这些路由字段必须迁移到 `cloud-api` 服务端权威 profile,本地 profile 不再决定 gateway/resource/workspace。
## 命令口径
统一 locator 语法为:
```text
device-pod-cli <devicePodId>:<surface>[:<resourcePath>] <operation> [args...]
```
MVP surface 固定为:
- `workspace`:源码、工程、构建产物和受控文件操作。
- `debug-probe`:下载、复位、探针状态和芯片 ID。
- `io-probe`UART、GPIO、AI/AO/DI/DO、状态采样和日志读取。
workspace 操作采用 busybox 风格白名单,不提供 `cmd` 子命令。已跑通的 CLI MVP 先开放 `ls``cat``rg``apply-patch``build``stat``find``head``tail``wc``upload``download``clean``artifact list` 作为后续扩展进入同一白名单模型。所有文件路径必须限制在 profile 声明的 workspace root 内。
示例:
```text
device-pod-cli device-pod-71-freq:workspace:/firmware ls
device-pod-cli device-pod-71-freq:workspace:/firmware/main.c cat --max-bytes 12000
device-pod-cli device-pod-71-freq:workspace:/firmware/main.c apply-patch < fix.patch
device-pod-cli device-pod-71-freq:workspace:/firmware build --profile debug
device-pod-cli device-pod-71-freq:debug-probe download --artifact build/app.hex --approved --reason "DEV smoke"
device-pod-cli device-pod-71-freq:debug-probe reset --approved --reason "DEV smoke"
device-pod-cli device-pod-71-freq:debug-probe chip-id
device-pod-cli device-pod-71-freq:io-probe:/uart/1 read --max-bytes 12000
device-pod-cli device-pod-71-freq:io-probe:/inner/gpio/pa1 read
```
`io-probe:/inner/...` 必须显式表示从 target 内部状态读取,例如寄存器、全局变量、debug memory 或固件导出的状态。默认 `io-probe:/gpio/pa1``io-probe:/uart/1` 等路径表示外部真实 I/O probe、仪器或另一个设备观测到的物理信号。验收证据中不得混淆 inner 和外部 I/O。
## 输出与权限
CLI 默认输出 JSON。成功和失败都必须包含 `devicePodId``targetId``surface``operation``traceId``operationId``profileHash``route``status``blocker``evidence` 和截断元数据。输出文本、串口日志和命令日志必须有 `maxBytes` 或分页边界。
下载、复位、写 I/O、修改 workspace 等动作属于 mutating operation,必须要求显式 approval 参数,并写入 reason。长耗时操作返回 `jobId`CLI 轮询或拉取 job output,不让一次 HTTP/gateway 调用长期阻塞。
## 开发方式
1. 先实现 profile schema、loader、locator parser 和 JSON 输出合同,用 fake profile 在本地单元测试覆盖成功、缺 profile、坏 profile、路径越界和未知 surface。
2. 实现 workspace busybox 操作和 fake gateway adapter,先在不接硬件时证明路径裁剪、输出截断和错误结构稳定。
3. 实现 debug-probe 与 io-probe 的 adapter 接口,先用 fake `device-host-cli` 返回 chip ID、UART 样例和下载 job 状态。
4. 在 D518 Windows 上开发自包含 `device-host-cli`,通过 `D518:win` 做真实 DAPLink、串口或下载器 smokeKeil、串口监控、mklink 和文件编辑 skill 只能作为实现参考,不作为运行时依赖。D518 侧只承载硬件上位机逻辑,不改变 G14 source truth。
5. 在 G14 code agent pod 中开发和验证 `device-pod-cli`code agent pod 不放完整 HWLAB 源码和 Git keyCLI 通过 skill 分发到预装位置,并在 skill 说明中写清仅适用于 HWLAB 内部 code agent。
6. fake 闭环通过后再做 G14 -> gateway -> D518 -> 硬件的最小 live smoke,然后把修复固化到源码、测试和长期参考。
## 调试方式
- `--dry-run` 只解析 profile、locator 和路由计划,不触发 gateway 或硬件动作。
- `--trace-id` 可传入外部 trace;未传入时 CLI 生成 trace,并在所有 adapter 输出中透传。
- `--verbose` 只展开结构化 adapter 阶段和截断摘要,不直接打印 secret 或无限日志。
- fake adapter 用于本地和 CIlive adapter 只在明确选择 profile route 时启用。
- 真实硬件问题先在 D518 `device-host-cli` 单独复现,再通过 `device-pod-cli` 验证端到端链路。
## 验收标准
MVP 通过至少需要满足:
- `.device-pod/<devicePodId>.json` 能被读取、校验、hash 并体现在每次 CLI JSON 输出中。
- workspace `ls/cat/rg/apply-patch/build` 在受控 root 内可用,路径越界、过大输出和未知命令有结构化失败;`artifact list` 进入后续扩展。
- `debug-probe chip-id/download/reset` 能通过 fake adapter 稳定返回 job/evidencelive smoke 至少证明一次真实 debug probe 路径可达。
- `io-probe:/uart/1 read``io-probe:/inner/... read` 在输出中明确标注外部/内部来源,不互相冒充。
- gateway 仍只是 cmd transportCLI 不暴露任意 shell、不接收泛化 `cmd` 子命令、不绕过 profile 访问硬件。
- 文档、CLI 帮助和 skill 说明明确写明该 CLI 只用于 HWLAB 内部 code agent,不适用于 UniDesk 外部开发者工作区。
-12
View File
@@ -1,12 +0,0 @@
# Device Pod Server MVP 历史计划
本文保留为历史计划入口。正式 v0.2 device-pod 接入规格已收敛到 [../reference/spec-device-pod.md](../reference/spec-device-pod.md),迁移计划见 [v02-device-pod-spec-migration.md](v02-device-pod-spec-migration.md)。
旧计划中“`device-pod-server``device-pod` 一一对应”和“code agent workspace `.device-pod/` 是 profile source-of-truth”的口径,只适用于早期 CLI MVP 讨论,不适用于正式多用户系统。
当前权威口径:
- 一个 `hwlab-device-pod` Deployment/Service 在 v0.2 第一阶段管理多个逻辑 `devicePodId`
- `cloud-api` 和 Postgres 中的 `device_pods.profile_json` 是正式 profile authority。
- `device-pod-cli` 只做 REST 客户端,不再用本地 profile 决定 gateway/resource/workspace。
- `hwlab-device-pod` 承接 job、freshness、blocker 和 gateway/device-host-cli adapter,不保存用户 grant。
@@ -1,35 +0,0 @@
# Device Pod 右侧看板与 fake service 方案
## 目标
- 将 Cloud Workbench 右侧区域收敛为 Device Pod 看板,默认只显示 summary。
- 看板内部不做展开/收起;用户点击 summary 卡片后,通过弹窗查看细节。
- 事件流降级为最简单的纯文本窗口,更新时不抢占用户正在滚动的位置。
- 当前先提供 `hwlab-device-pod` fake 服务,完成前端信息模型、Cloud API fallback/proxy 与静态合同闭环。
## 前端规划
- 右侧固定入口为 `aside#device-pod-sidebar`,包含 Pod Summary、Target、Workspace、Debug、IO 和纯文本事件流。
- Summary 卡片只展示关键字段;完整 payload 通过 `dialog#device-detail-dialog` 展示,避免在右侧看板内部嵌套折叠面板。
- 事件流使用 `pre#device-event-text`,滚动容器使用 `overscroll-behavior: contain`,并记录 `followEvents``unreadEvents` 与用户滚动活动时间。
- 前端默认不展示旧硬件拓扑面板,不连接旧模拟硬件拓扑,不提供浏览器侧泛化硬件写入口。
- 删除旧 `web/hwlab-cloud-web/gate-summary.mjs` 生成型前端拓扑资产,以及生成它的 `scripts/export-web-gate-summary.mjs`/`web:summary` 入口,避免 gateway-simu、box-simu 和 patch-panel 通过前端资产回流。
## 服务规划
- 新增 `cmd/hwlab-device-pod/main.mjs`,默认端口 `7601`,先服务 fake 数据。
- 新增 `internal/device-pod/fake-data.mjs` 作为 fake 数据与 REST payload 构造器,覆盖列表、status、events、chip-id、UART 状态和 UART tail。
- `hwlab-cloud-api``/v1/device-pods` 做 upstream proxyupstream 不可用或未配置时回退到 fake payload,前端不直接连接 Device Pod 后端。
## 部署规划
- `internal/protocol`、deploy manifest、k8s service/workload、health contract 与 artifact catalog 均登记 `hwlab-device-pod`
- DEV 环境默认 `HWLAB_DEVICE_POD_ID=device-pod-71-freq``HWLAB_DEVICE_POD_PORT=7601`
- 该阶段只证明 fake service 与前端右侧看板合同,不声明真实设备闭环通过。
## 验收标准
- `node web/hwlab-cloud-web/scripts/check.mjs` 只按 Device Pod 右侧看板、summary 弹窗、纯文本事件流和 fake service 合同检查。
- `node --check` 覆盖新增 fake 数据、Device Pod 服务、Cloud API、前端 app、live-status 与 check 脚本。
- 右侧看板 HTML 中不存在内部 `<details>` 展开/收起结构;旧硬件面板 DOM 与旧硬件 API 调用不作为验收目标。
- Cloud Web runtime/dist 与 L6 Web smoke 不再依赖 `gate-summary.mjs`,也不再断言 gateway-simu、hwlab-box-simu 或 hwlab-patch-panel 前端拓扑。
-178
View File
@@ -1,178 +0,0 @@
# HWLAB v0.2 namespace 与 CI/CD 扩容计划
本文是 `v0.2` 分支上的执行计划,用于把 `hwlab-v02` 作为 G14 上的独立运行面接入当前 Tekton + GitOps + Argo CD 体系。目标是只做加法扩容,保持现有 G14 DEV/PROD 100% 稳定。长期规格、命名、硬边界和验收标准以 [../reference/spec-v02-cicd.md](../reference/spec-v02-cicd.md) 为准;本文只保留迁移阶段、风险处理和执行顺序。
## 固定命名
- Source branch`v0.2`,从当前 `G14` 分支 fork。
- Source workspace`G14:/root/hwlab-v02`,固定跟踪 `origin/v0.2`
- Runtime namespace`hwlab-v02`
- GitOps branch:规划使用 `v0.2-gitops`,避免写入 `G14-gitops` 的 DEV/PROD desired state。
- Artifact catalog:规划使用 `v0.2-gitops:deploy/artifact-catalog.v02.json`;它是 CI/CD 生成物和 artifact identity truth,不在 `v0.2` source branch 跟踪或手写维护。
- Runtime path:规划使用 `v0.2-gitops:deploy/gitops/g14/runtime-v02`;它是 rendered desired state,不在 `v0.2` source branch 跟踪。
- Argo CD Application:规划使用 `hwlab-g14-v02`
- Public FRP entryCloud Web `http://74.48.78.17:19666/`API/live `http://74.48.78.17:19667/health/live`
## 不变边界
- 不删除、不重命名、不复用 `hwlab-dev``hwlab-prod` namespace。
- 不改写现有 `G14` branch poller、`G14-gitops` DEV/PROD runtime path 或 `hwlab-g14-dev` / `hwlab-g14-prod` Argo Application。
- 不复用 DEV/PROD 的 FRP 端口、Secret、DB 凭据、PVC 或运行态热修资源。
- 不清理或重构 `G14` source branch 里已经存在的历史生成物;本计划只规定 `v0.2` 起新增生成物彻底隔离到 GitOps branch。
- 不在 `v0.2` source branch 新增或维护 `deploy/artifact-catalog.v02.json``deploy/gitops/g14/runtime-v02/*` 或 rendered Tekton/Argo runtime manifests。
- 阻碍 `v0.2` 扩容的旧 DEV/D601/main 门禁一律从 `v0.2` 调用链彻底拆除;不做兼容性迁移、fallback、legacy mode、绕路或在旧门禁上叠加例外。
- 不在 master server 上运行仓库级 check、browser smoke、镜像构建或集群写操作。
- 在计划被 issue 追踪并人工确认前,不执行 namespace 创建、Argo sync、FRP 切流或 Tekton 控制面 apply。
## 技术决策:v0.2 生成物隔离
`G14` 分支上现有 source 里的历史生成物保持不动,避免为了整理历史而影响 DEV/PROD 稳定性。从 `v0.2` 开始采用更严格的 source/GitOps 分层:source branch 只存人类意图、源码、模板、脚本和计划;GitOps branch 存 CI/CD 生成的 artifact catalog、runtime manifests 和 Argo 可消费的 desired state。
`v0.2` source branch 可以包含:
- `deploy/deploy.json` 或等价 lane 配置,作为 human-authored runtime intent。
- k8s 模板、render 脚本、CI/CD helper 和文档计划。
- artifact catalog schema、示例或说明,但示例不得伪装成当前发布真相。
`v0.2-gitops` branch 必须包含:
- `deploy/artifact-catalog.v02.json`,记录 image tag、digest、source commit、component commit/hash、publish/reuse evidence。
- `deploy/gitops/g14/runtime-v02/*`,记录 Argo CD 实际消费的 rendered manifests。
- 必要的 generated rollout metadata,但不得包含 Secret 值。
CI/CD 的初始化规则:Tekton 执行 `v0.2` lane 时必须先读取 `v0.2-gitops:deploy/artifact-catalog.v02.json`。首次初始化时若该文件尚不存在,只允许由 `v0.2` lane 的正式初始化步骤创建第一版 catalog;不得 fallback 到 `G14` source catalog、`G14-gitops` catalog、DEV runtime path 或 source branch 生成物。publish 成功后,刷新后的 catalog 和 runtime manifests 只提交到 `v0.2-gitops`,不得写回 `v0.2` source branch。
真相源划分如下:
| 内容 | `v0.2` source branch | `v0.2-gitops` branch |
|---|---|---|
| 人类运行配置 | 是,`deploy/deploy.json` 或 lane 配置 | 否 |
| 模板和 render 逻辑 | 是 | 否 |
| artifact identity | 否 | 是,`deploy/artifact-catalog.v02.json` |
| rendered runtime manifests | 否 | 是,`deploy/gitops/g14/runtime-v02/*` |
| Argo CD 消费路径 | 否 | 是 |
这个决策的目标是避免 `v0.2` source branch 出现“看似可手改、实际由 CI 生成”的半真相文件;后续所有复用、跳过构建、digest 对齐和 runtime identity 判断都必须以 GitOps branch 的 artifact catalog 为输入。
## 陈旧门禁与处理策略
扩容 `v0.2` 时会遇到两类历史依赖:核心 artifact/GitOps 机制需要保留并参数化;旧 DEV-only 自检、preflight、guard 和报告校验不得进入 `v0.2` 路径。凡是阻碍 `v0.2` 的旧门禁,处理方式只有从 `v0.2` 调用链删除;不做兼容性迁移、不做 fallback、不保留 legacy mode、不在旧门禁上加例外。
必须参数化保留的核心路径:
| 位置 | 当前问题 | v0.2 处理 |
|---|---|---|
| `scripts/g14-gitops-render.mjs` | 默认 `G14``G14-gitops``deploy/artifact-catalog.dev.json``runtime-dev`/`runtime-prod`。 | 增加显式 lane/source/gitops/catalog/runtime/namespace/endpoint 参数;`v0.2` 只写 `v0.2-gitops`。 |
| `scripts/refresh-artifact-catalog.mjs` | catalog path、namespace、environment、endpoint 被 DEV-only 断言固定。 | 改成 lane contract`v0.2` 从 GitOps checkout 读写 `deploy/artifact-catalog.v02.json`,不读写 source catalog。 |
| `scripts/src/g14-ci-plan-lib.mjs` | 复用判断依赖 artifact catalog;默认路径仍是 DEV catalog。 | 保留复用能力,但 `v0.2` 必须传入 GitOps catalog pathcatalog 缺失只能触发 `v0.2` 正式初始化或失败,不得回退到 DEV/source catalog。 |
| `scripts/artifact-publish.mjs` / `scripts/g14-artifact-publish.mjs` | preflight 仍把 `hwlab-dev`、DEV catalog 和 DEV-only contract 作为唯一合法目标。 | 保留 build/publish helper`v0.2` 调用链必须删除这类 DEV-only preflight,只在 build/publish 自然写入点做最小内联断言。 |
不应进入 `v0.2` 发布门禁的陈旧路径:
| 位置 | 陈旧点 | 处理 |
|---|---|---|
| `scripts/src/dev-gate-preflight.mjs` | 默认 `origin/main``hwlab-dev`、D601/kubectl 口径和旧 `16666/16667` DEV 入口。 | 从 `v0.2` 发布调用链删除;不得改造成 `v0.2` 兼容门禁。 |
| `scripts/src/artifact-runtime-readiness-guard.mjs` | 以 source catalog、latest-main 和 DEV runtime identity 为核心假设。 | 从 `v0.2` 发布调用链删除;如需检查,新增只读 `v0.2` 最小 runtime identity 检查,不复用旧 guard。 |
| `scripts/validate-artifact-catalog.mjs` | 强制校验 `deploy/artifact-catalog.dev.json``hwlab-dev`。 | 不在 `v0.2` 路径运行;不把它改成多 lane 兼容脚本。 |
| `scripts/src/deploy-desired-state-plan.mjs` | 默认从 source 读取 DEV catalog,容易形成 source desired-state 幻觉。 | 不作为 `v0.2` apply 前门禁;若阻碍扩容,直接移出 `v0.2` 发布流程。 |
| `scripts/src/dev-cloud-workbench-smoke-lib.mjs``scripts/src/rpt004-mvp-e2e-harness.mjs`、M3/M4 DEV smoke | 固定 DEV 端口、DEV-LIVE 术语和历史报告 schema。 | 不复用为 `v0.2` gate;必要时新增独立 `v02` smoke,只验证 `19666/19667``hwlab-v02`。 |
| `scripts/validate-contract.mjs`、旧 `deploy/README.md` / `deploy/master-edge/*` | 仍含历史 `16666/16667` 或 D601 DEV 合同。 | 不让这些旧合同阻塞 `v0.2`;若某项仍被 CI 调用,先从 `v0.2` CI 删除该调用。 |
| source branch 中的 rendered `deploy/gitops/g14/tekton/*` | 可能是历史生成快照,不是 Argo/Tekton 当前真相。 | `v0.2` 不在 source 更新这些生成物;只改 render 入口和 GitOps branch 输出。 |
`v0.2` 不新增综合 preflight 或大范围 guard。只保留以下硬边界,并优先在已有自然写入点做内联断言:render 断言 runtime path/namespacepromote 断言 GitOps branch/changed pathsArgo spec 断言 Application destination,验收只看 `19666/19667``hwlab-v02` identity。不要为每一条设计约定再写一个独立 gate。
- source branch 必须是 `v0.2`GitOps branch 必须是 `v0.2-gitops`runtime namespace 必须是 `hwlab-v02`
- runtime path 必须是 `deploy/gitops/g14/runtime-v02`Argo Application 必须指向 `v0.2` GitOps lane 和 `hwlab-v02`
- `v0.2` source branch 在 publish 后不得出现 `deploy/artifact-catalog.v02.json``deploy/gitops/g14/runtime-v02/*` 变更。
- 文档、issue、trace 和 report 只出现 SecretRef 名称和 key,不出现 Secret 值。
- 公网验收只使用 `74.48.78.17:19666/19667`,不得把 `17666/17667``18666/18667` 作为 `v0.2` 通过证据。
## G14 与 v0.2 CI/CD 共存风险
G14 与 `v0.2` 可以共享 G14 k3s、Tekton controller、Argo CD controller、本地 registry 和 Git 仓库,但不得共享发布真相、默认入口和生成物。共存原则是:共享底层设施,隔离 source branch、GitOps branch、artifact catalog、runtime path、namespace、Argo Application、poller/reconciler/PipelineRun 名称和 FRP 入口。
| 风险 | 具体表现 | 化解方式 |
|---|---|---|
| 控制面资源覆盖 | `v0.2` render/apply 覆盖 `hwlab-g14-ci-image-publish``hwlab-g14-branch-poller``hwlab-g14-control-plane-reconciler`。 | `v0.2` 使用独立资源名,例如 `hwlab-v02-ci-image-publish``hwlab-v02-branch-poller``hwlab-v02-control-plane-reconciler`;共享 Tekton controller,不共享具体 Pipeline/CronJob。 |
| 默认值漂移 | 为支持 `v0.2` 修改 G14 默认值,导致现有 DEV/PROD 行为变化。 | G14 默认值完全不动;`v0.2` 必须显式传入 lane/source/gitops/catalog/runtime/namespace/endpoint。 |
| GitOps 写错分支 | `v0.2` promotion 误 push 到 `G14-gitops`。 | promote 前硬校验 `sourceBranch=v0.2``gitopsBranch=v0.2-gitops`,且 changed paths 只能在 `deploy/artifact-catalog.v02.json``deploy/gitops/g14/runtime-v02/**`。 |
| runtime path 串线 | `v0.2` 写入 `runtime-dev``runtime-prod`。 | `v0.2` render 输出路径硬限制为 `deploy/gitops/g14/runtime-v02`;发现 DEV/PROD runtime path 变更直接失败。 |
| artifact catalog 串线 | `v0.2` 读取或复用 `deploy/artifact-catalog.dev.json``G14-gitops` catalog 或 source branch 生成物。 | `v0.2` 只读写 `v0.2-gitops:deploy/artifact-catalog.v02.json`;缺失只能正式初始化或失败,不 fallback。 |
| 旧门禁阻塞 | DEV/D601/main 门禁拦住 `v0.2` 发布。 | 从 `v0.2` 调用链删除旧门禁;需要保护时只在自然写入点做最小内联断言。 |
| Argo Application 指错 | `hwlab-g14-v02` 指到 `G14-gitops``runtime-dev``hwlab-dev`。 | Application spec 固定为 `v0.2-gitops:deploy/gitops/g14/runtime-v02`destination 固定为 `hwlab-v02`。 |
| namespace 资源串用 | Secret、PVC、ServiceAccount、FRP Deployment 或 runtime Service 复用 DEV/PROD。 | namespace 独立;runtime SecretRef 只在 `hwlab-v02` 内解析;cluster-scoped 资源必须独立命名或禁止进入 `v0.2` runtime。 |
| registry tag/digest 混淆 | G14 和 `v0.2` 使用短 SHA tag 时被误判为同一运行态。 | `v0.2` 镜像 tag 使用完整 source commitIdruntime manifest 使用 digest pinlane 身份记录在 catalog 和 runtime annotation。不要把 lane-specific 配置 bake 进镜像。 |
| 清理任务误删 | stale PipelineRun cleanup、registry GC 或 Argo prune 误触 G14 DEV/PROD。 | 初期不新增自动 registry GC;如后续启用 cleanupselector 必须带 lane labelregistry GC 保护集取 `G14-gitops``v0.2-gitops` 的 digest union。 |
| 并发资源争抢 | 两个分支同时 buildG14 DEV rollout 变慢。 | `v0.2` 初期使用较低 poller 频率或手动触发;设置 Pipeline resources requests/limitsG14 DEV/PROD 优先级高于 `v0.2`。 |
| 观测混淆 | 把 `17666/17667``18666/18667` 的结果当成 `v0.2` 通过。 | `v0.2` 验收只认 `19666/19667`health payload 必须能看到 lane、namespace 或 revision 与 `hwlab-v02` 对齐。 |
`v0.2` 第一阶段不得做“一个 Pipeline 入口同时兼容两个分支”的设计。正确做法是:G14 保持现有 poller、reconciler、pipeline 和 GitOps branch 不变;`v0.2` 新增独立 poller、reconciler、pipeline 和 GitOps branch,复用底层脚本库、工具镜像、registry 和 controller。共享实现能力,不共享状态、默认入口或生成物。
## 扩容前决策表
开始创建 namespace、改 Tekton/Argo 或触发 `v0.2` CI/CD 前,先按下表定案。该表不是新增门禁清单;除硬边界外,设计约定和 runbook 不得自动实现为新的 preflight、guard、gate 或报告生成器。
| 决策项 | 建议定案 | 性质与降噪要求 |
|---|---|---|
| CI 控制面命名 | 使用独立 `hwlab-v02-*``hwlab-v02-ci-image-publish``hwlab-v02-branch-poller``hwlab-v02-control-plane-reconciler``hwlab-v02-ci-poll-<short12>`。 | 硬边界;只防覆盖 G14 资源,不扩展成大范围命名审计。 |
| ServiceAccount/RBAC | 推荐新建 `hwlab-v02-tekton-runner`,权限只覆盖 `v0.2` GitOps 写入、PipelineRun 创建和 `hwlab-v02` 运行面观察。 | 设计边界;不做复杂权限 gate,先通过清晰命名和最小 RBAC manifest 表达。 |
| `v0.2-gitops` 初始化 | 新建独立分支 `v0.2-gitops`;首版只放 `deploy/artifact-catalog.v02.json``deploy/gitops/g14/runtime-v02/*`;提交身份使用 CI/GitOps bot。 | 硬边界;catalog 缺失只能正式初始化或失败,不 fallback 到 G14/DEV。 |
| `deploy.json` lane 表达 | 在 `v0.2` source branch 新增显式 `lanes.v02` 或等价 lane 字段,由 render `--lane v02` 读取;不把现有 `dev``prod` 改义成 `v0.2`。 | 设计定案;不要为 schema 选择额外做兼容迁移路线。 |
| 镜像 tag | `v0.2` 镜像 tag 使用完整 40 位 source commitIdruntime 以 digest pin 为部署身份;catalog 记录 lane/sourceBranch/gitopsBranch/sourceCommitId/digest。 | 简化策略;不引入 `v02-<short>` tag,不把 lane 差异 bake 进镜像。 |
| 构建输入边界 | 同一 commit 对同一 service 应生成同一镜像;lane 差异放入 manifest/env/SecretRef/namespace/FRP/DB 配置。 | 设计边界;若同 commit 生成不同镜像,先修构建边界,不用 lane tag 掩盖。 |
| SecretRef | `hwlab-v02` 使用独立 Secret 对象;key 名可以沿用服务合同,值不得复用 DEV/PROD,文档只记录对象名和 key。 | 硬安全边界;只禁止 Secret 值外泄,不做 Secret 内容读取 gate。 |
| 数据面 | 推荐独立 DB user + 独立 databasePVC 独立;如后续选择 schema 隔离,必须在计划中单独说明原因。 | 设计定案;不把 DB 方案选择变成 CI gate。 |
| Argo CD | 新建 `hwlab-g14-v02`source 固定 `v0.2-gitops:deploy/gitops/g14/runtime-v02`destination 固定 `hwlab-v02`。 | 硬边界;通过 Application spec 表达,不新增平行 Argo 审计脚本。 |
| Argo prune | 允许在 `hwlab-v02` Application 范围内 prune;不得跨 namespace 或管理 DEV/PROD 资源。 | 运行策略;不做 apply 前大检查,靠 Application scope 和 resource labels 限定。 |
| FRP | frpc 名称用 `hwlab-v02-frpc`,只暴露 `19666/19667`Service 指向 `hwlab-v02` 内 Cloud Web 和 edge/API。 | 硬入口边界;验收只认 v02 端口。 |
| 最小验收 | 只看 `hwlab-g14-v02` revision/sync、`hwlab-v02` 长驻 workload ready、`19666/19667` health/runtime identity。 | 验收口径;旧 DEV/M3/RPT smoke 不进入 `v0.2` gate。 |
| 旧门禁 | DEV/D601/main 门禁凡阻碍 `v0.2`,直接从 `v0.2` 调用链删除。 | 硬治理原则;不做兼容迁移、fallback、legacy mode 或旧门禁例外。 |
| 资源策略 | 初期手动触发或低频 poller;限制 `v0.2` 构建并发和 CPU/memoryG14 DEV/PROD 优先。 | 运行策略;不作为发布 gate。 |
| 清理策略 | 初期不启用新增自动 registry GC;若后续启用,cleanup selector 必须带 `lane=v02`registry GC 保护集取 `G14-gitops` + `v0.2-gitops` digest union。 | 运行手册;不是扩容前 gate。 |
| 回滚/暂停 | 失败时先停 `hwlab-v02-branch-poller`,再 suspend/delete `hwlab-g14-v02`,最后处理 `hwlab-v02` runtime 资源。 | runbook;不阻塞首次部署,且不得触碰 DEV/PROD。 |
| G14 到 `v0.2` 同步 | bugfix 用显式 cherry-pick 或人工 merge,不做自动同步,不让 `v0.2` 反向影响 G14。 | 分支治理;不做自动 gate。 |
| 变更路径 | 文档和计划可直推 `origin/v0.2`namespace、Argo、Tekton、Secret、DB、FRP 和 rollout 变更必须引用 issue 和 plan 分步执行。 | 执行纪律;不引入额外 PR/gate 要求。 |
## 实施阶段
1. 文档与 issue 基线
- 确认 `origin/G14``origin/v0.2` 都包含 `v0.2` 加法扩容长期参考。
- 创建 GitHub issue 引用本文,作为 `hwlab-v02` namespace 与 CI/CD 接入的跟踪入口。
2. Namespace 与基础 Secret 规划
- 在 G14 k3s 中新增 `hwlab-v02` namespace。
- 为 `hwlab-v02` 准备独立 SecretRef`hwlab-v02-postgres/POSTGRES_PASSWORD``hwlab-cloud-api-v02-db/database-url``hwlab-v02-code-agent-provider/openai-api-key``hwlab-v02-code-agent-codex-auth/*`;key 名按服务合同保留,Secret 对象名与值不得复用 DEV/PROD。
- Secret 计划只记录对象名和 key,不在文档、issue、日志或 trace 中写入值。
3. GitOps desired state 扩容
- 扩展 render 支持显式 lane 参数:source branch `v0.2`、GitOps branch `v0.2-gitops`、catalog `deploy/artifact-catalog.v02.json`、runtime path `deploy/gitops/g14/runtime-v02`、namespace `hwlab-v02`
- render 在执行时从 `v0.2-gitops` 读取上一版 catalogcatalog 缺失时只能执行 `v0.2` 正式初始化或失败,不能 fallback 到 DEV/G14 catalog。
- 新增 `v0.2-gitops` 生成分支或等价隔离 GitOps 目标;不得把 v02 生成物写入 DEV/PROD runtime path,也不得写回 `v0.2` source branch。
- 新增 frpc runtime manifest,只暴露 `19666/19667`,内部服务端口继续按现有 Cloud Web `8080`、edge/API `6667` 约定。
4. Tekton lane 扩容
- 在 `hwlab-ci` 中新增 `v0.2` 独立 poller/reconciler/Pipeline,不复用或覆盖现有 G14 控制面资源名。
- `v0.2` PipelineRun 前缀使用 `hwlab-v02-ci-poll-<short12>`,方便和 `hwlab-g14-ci-poll-<short12>` 区分。
- Pipeline 必须 checkout `v0.2` source 和 `v0.2-gitops` generated statebuild/publish helper 可复用现有工具镜像、registry 和 BuildKit 机制,但产物 catalog、GitOps branch、runtime path 必须隔离。
- 镜像 tag 使用完整 source commitId,最终部署 identity 以 digest pin 为准。
5. Argo CD 扩容
- 新增 `hwlab-g14-v02` Applicationsource 指向 `v0.2` 专属 GitOps lanedestination 指向 `hwlab-v02`
- 不修改 `hwlab-g14-dev``hwlab-g14-prod` 的 source path、revision、namespace 或 sync policy。
- 首次同步先 dry-run / diff / health 观察,再进入真实 sync。
6. `deploy.json` 扩容
- 在 `v0.2` 分支上新增显式 `lanes.v02` 或等价 lane 配置,服务清单以 `hwlab-v02` 为目标 namespace。
- 不把现有 `dev``prod` 环境静默改义为 v02。
- `deploy.json` 只承载 human-authored runtime intentimage digest、publish state、source commit、reuse evidence 不得写入 `deploy.json`
- 如果 render 需要新增 schema 字段,字段必须向后兼容现有 DEV/PROD 配置,并在 v02 lane 中显式启用。
7. 验收
- `tran G14:k3s kubectl -n hwlab-v02 get deploy,sts,svc,pod -o wide` 显示长驻 workload ready。
- `tran G14:k3s kubectl -n argocd get application hwlab-g14-v02` 显示目标 revision、sync 和 health 与 v02 GitOps lane 对齐。
- `http://74.48.78.17:19666/` 返回 v02 Cloud Web。
- `http://74.48.78.17:19667/health/live` 返回 v02 runtime healthpayload 的 namespace、revision 或 runtime identity 能和 `v0.2` lane 对齐。
## 回滚边界
`v0.2` 是新增运行面。若接入失败,回滚应只删除或暂停 `hwlab-v02` lane 的新增 Application、poller、reconciler、runtime path、FRP 入口或 namespace 资源;不得回滚、删除或重启现有 `hwlab-dev` / `hwlab-prod` 运行面。
-136
View File
@@ -1,136 +0,0 @@
# v0.2 Device Pod 正式接入迁移计划
本文记录当前 v0.2 源码到 [../reference/spec-device-pod.md](../reference/spec-device-pod.md) 的迁移路径。目标是把已经跑通的 `device-pod-cli -> cloud-api/gateway -> device-host-cli` 最小闭环,迁移成正式多用户系统中的 `cloud-api` 授权 REST 和 `hwlab-device-pod` 设备业务服务。
## 当前态
从 v0.2 源码看,当前实现仍处于 fake service + CLI MVP 混合状态:
- `cmd/hwlab-device-pod/main.mjs` 只提供 GET fake payload 和 `/health`,不连接真实硬件,不执行 job。
- `internal/device-pod/fake-data.mjs` 构造 `/v1/device-pods``/status``/events``/debug-probe/chip-id` 和 UART tail 的 fake 数据。
- `internal/cloud/server.mjs``/v1/device-pods` 做 upstream proxyupstream 不可用时回退 fake payload,没有授权过滤、profile authority、job route 或 lease。
- `tools/device-pod-cli.mjs` 从 code agent workspace 的 `.device-pod/` 读取 profile,并直接调用 `cloud-api /v1/rpc/hardware.invoke.shell`
- `skills/device-pod-cli/assets/device-host-cli.mjs` 承载了真实业务:workspace 文件操作、Keil build/download、pyOCD chip-id/reset、UART read/write 和 host 侧 job 状态。
- `deploy/k8s/base/workloads.yaml` 已有 `hwlab-device-pod` Deployment,当前是 `replicas=1` 的 fake 服务。
- G14 集群当前 `hwlab-dev` 存在 running `hwlab-device-pod` Service/Pod`hwlab-v02` namespace 尚未落地 device-pod 运行面。
## 目标差距
| 领域 | 当前态 | 规格目标 |
| --- | --- | --- |
| Profile authority | code agent 本地 `.device-pod/*.json` 决定 gateway/resource/workspace | `cloud-api` DB 中 `device_pods.profile_json` 是唯一权威 |
| CLI | 读取 profile 并拼 RPC/gateway shell | 只把 selector 转成 cloud-api REST 请求 |
| Device service | fake GET payload | 多 `devicePodId` registry、profile runtime validation、job/freshness/blocker |
| Cloud API | proxy/fake fallback | auth、grant、lease、profile admin API、job proxy |
| K8s | 一个 fake Deployment | 一个正式 Deployment 管多个 `devicePodId` |
| 用户安全 | 本地 profile 可被 code agent 改写 | code agent 无法改变 gateway route 或硬件资源边界 |
## 迁移原则
- 不引入单独 user-management 或 device-profile 微服务;profile authority 先放在 `cloud-api` 和 Postgres。
- 不为每个 device pod 创建独立 k8s Deployment/Service;第一阶段一个 `hwlab-device-pod` 管多个逻辑 `devicePodId`
- 不把本地 `.device-pod/*.json` 做兼容权威路径;正式模式只允许本地 hint/cache。
- 不让 `hwlab-device-pod` 接受用户、code agent 或浏览器上传的 profile 执行 job。
- 不把 fake fallback 标为 livefake 只用于 UI/fixture/降级展示。
## 阶段 1Schema 收口
在多用户迁移中同步调整 `device_pods` 表:
- 使用 `profile_json` 保存权威 profile。
- 使用 `profile_hash` 保存规范化 profile hash。
- 删除或不新增 `profile_ref``gateway_ref``device_pod_json` 这类容易分散权威的字段。
- `device_pod_grants` 只表达用户是否拥有完整使用权,不保存 profile 和 capability。
不兼容处理:早期 `.device-pod/<devicePodId>.json` 不导入为普通用户可写配置;如需复用,只能由 admin 一次性导入为 server-side profile。
## 阶段 2cloud-api Profile 和 Grant API
`hwlab-cloud-api` 内实现:
- `POST /v1/admin/device-pods`:创建 device pod 和 profile。
- `PUT /v1/admin/device-pods/{devicePodId}`:更新 profile、状态和名称。
- `GET /v1/device-pods`:按 `admin/user + device_pod_grants` 过滤。
- `GET /v1/device-pods/{devicePodId}/status`:授权后读取状态。
- `POST /v1/device-pods/{devicePodId}/jobs`:授权、必要时 lease、转发内部 service。
cloud-api 返回给普通用户的 profile 只能是脱敏摘要和 `profileHash``route.gatewaySessionId``resourceId``hostWorkspaceRoot``hostCli`、probe UID 和串口端口不进入普通用户响应。
不兼容处理:未登录或未授权访问 `/v1/device-pods*` 返回 `401/403`,不再回退到 default fake device pod。
## 阶段 3hwlab-device-pod 多设备服务
`cmd/hwlab-device-pod/main.mjs` 从 fake GET 改造成正式服务:
- 维护内存 registry`devicePodId -> profileHash/status/freshness/jobs`
- 提供内部 RESTstatus、short probe、job create/status/output/cancel。
- 从 cloud-api 内部请求接收 profile snapshot,或用内部服务凭据向 cloud-api 拉取 profile。
- 调用现有 gateway transport 和 Windows 侧 `device-host-cli`
- 解析 `device-host-cli` JSON 输出,统一 blocker、bounded output、freshness 和 evidence 字段。
`hwlab-device-pod` 不保存用户 grant,不判断用户身份;它只信任来自 cloud-api 的内部服务请求。内部服务凭据不得挂载进 code agent worker/session Pod。
不兼容处理:普通用户和 code agent 直连 `hwlab-device-pod` Service 不是支持路径;缺少内部服务凭据时返回 `401/403`
## 阶段 4device-pod-cli REST 化
`tools/device-pod-cli.mjs` 改为 1:1 REST 客户端:
- selector parser 和 JSON 输出合同可以复用。
- profile loader 降级为 hint/cache loader;正式执行只接受 `devicePodId`、operation、args 和 reason。
- 删除或禁用正式路径中的 `/v1/rpc/hardware.invoke.shell` 直调。
- `doctor` 改为检查 cloud-api 可见 device pod、profileHash、授权状态和 REST route,而不是要求本地 profile 可写。
不兼容处理:旧 profile bootstrap、uploadHostCli、uploadProfile 仍可保留在历史/维修命令中,但不能作为正式用户操作的默认下一步。
## 阶段 5:复用 device-host-cli 业务
短期不要重写 Windows 侧硬件能力。`hwlab-device-pod` 通过 gateway 调用已存在的 `device-host-cli`
- `workspace ls/cat/rg/apply-patch/build`
- `debug-probe status/chip-id/download/reset/launch-flash`
- `io-probe ports/read/write/read-after-launch-flash`
`device-host-cli` 仍部署在 Windows workspace 的 `tools\device-host-cli.mjs`,但其路径来自 server-side profile,不来自 code agent 本地文件。
## 阶段 6Cloud Web 和 Admin UI
Cloud Web 调整:
- 普通用户只显示授权 device pod。
- admin 增加 device pod 创建/更新/禁用、profile 编辑、grant 授权/撤销的最小 UI。
- Device Pod 右侧看板显示 `profileHash`、status、freshness、chip-id、UART tail 和 job 状态。
- fake fallback 必须明确标记 fake,不参与 DEV-LIVE 判定。
## 阶段 7v0.2 部署面
`hwlab-v02` namespace 中部署:
- 一个 `hwlab-device-pod` Deployment`replicas=1`
- 一个 `hwlab-device-pod` ClusterIP Service。
- cloud-api 和 device-pod 共享的内部服务凭据 Secret,但不挂载给 code agent session Pod。
- cloud-api 指向 v0.2 独立 Postgres/Secret,不复用 `hwlab-dev` pgdata。
不做 per-device Deployment/Service。未来只有在设备数量、隔离要求或资源差异明确出现后,才考虑 shard 或 per-device workload。
## 微服务调整
| 微服务 | 调整 |
| --- | --- |
| `hwlab-cloud-api` | 增加 profile authority、admin device-pod API、grant/lease、job proxy、脱敏 profile 响应。 |
| `hwlab-device-pod` | 从 fake GET 改成多 devicePodId REST/job service,调用 gateway/device-host-cli。 |
| `device-pod-cli` | 从本地 profile 执行器改成 cloud-api REST 客户端;本地 profile 只作 hint/cache。 |
| `device-host-cli` | 保持 Windows 侧业务能力,后续按真实硬件问题局部增强。 |
| `hwlab-cloud-web` | 增加 admin profile/grant UI,普通用户视图按授权过滤。 |
| `hwlab-agent-worker` | 为 code agent 提供 session-scoped cloud-api credential,不提供 gateway route/profile secret。 |
| GitOps/render | v0.2 新增 device-pod internal token Secret、env 注入和 `hwlab-v02` Service/Deployment。 |
## 最小验证
- 修改 code agent 本地 `.device-pod/*.json` 不能改变正式 device operation 的 gateway/resource/workspace。
- 未授权 `user` 调用 `/v1/device-pods/{devicePodId}/jobs` 返回 `403`
- 授权用户通过 `device-pod-cli` 发起 `workspace.build` 时,请求路径是 `/v1/device-pods/{devicePodId}/jobs`
- `hwlab-device-pod` 能在同一进程中管理至少两个 fake 或 real-profile `devicePodId`
- `debug.chip-id``io.uart.read``workspace.build` 的响应包含同一 `profileHash``traceId``operationId``freshness` 和 bounded output metadata。
- code agent session Pod 中不存在可用于调用内部 `hwlab-device-pod` profile/job API 的服务凭据。
- fake fallback 响应不会被前端或 health 判定为正式 DEV-LIVE device-pod 证据。
-145
View File
@@ -1,145 +0,0 @@
# v0.2 多用户访问迁移计划
本文记录 v0.2 当前源码状态、与目标用户和权限管理规格的差距,以及推荐迁移路径。长期目标和稳定判定标准以 [../reference/spec-user-access.md](../reference/spec-user-access.md) 为准。
## 当前态
从 v0.2 源码看,当前系统还没有真正的多用户访问控制:
- `docs/reference/spec-user-access.md` 已定义 `admin/user`、session owner 和 device pod grant 的目标规格,但还没有对应实现。
- `internal/db/migrations/0001_cloud_core_skeleton.sql` 已有 `projects``gateway_sessions``hardware_operations``audit_events``agent_sessions``worker_sessions``agent_trace_events``evidence_records` 和 migration ledger;没有 `users``user_sessions``device_pods``device_pod_grants``device_leases``agent_sessions` 也没有 `owner_user_id`
- `internal/db/runtime-store.mjs` 支持 memory/postgres runtime store 和 readiness,但主要服务 L1 硬件 runtime 数据;用户身份和授权尚未进入 runtime store。
- `web/hwlab-cloud-web/auth.mjs` 是轻量登录前端,默认 `admin/hwlab2026`,并有 local session fallback;它不是正式用户体系。
- `internal/dev-entrypoint/cloud-web-routes.mjs` 仍把 `POST /v1/agent/chat``POST /v1/agent/chat/cancel``GET /v1/agent/chat/result/*``GET /v1/agent/chat/trace/*` 视为 public proxy route,多用户下必须收敛为 auth-required。
- `internal/cloud/code-agent-session-registry.mjs` 以内存 Map 维护 session/conversation/facts,没有 owner、用户 session、Postgres 持久归属或跨 Pod 恢复。
- `internal/cloud/server.mjs``/v1/device-pods` 只是代理 `hwlab-device-pod` 或回退 fake payload,没有按 actor 过滤,也没有 profile authority、POST job 或 lease 权限入口。
- `cmd/hwlab-device-pod/main.mjs``internal/device-pod/fake-data.mjs` 当前只提供 fake GET 数据,不连接真实硬件,也不持久化 device pod 管理数据。
- `tools/device-pod-cli.mjs` 当前从 code agent workspace 的 `.device-pod/` 读取 profile,并直接调用 `/v1/rpc/hardware.invoke.shell`;正式多用户接入后,本地 profile 不能继续作为 gateway/resource/workspace 的权威来源。
- G14 当前集群里 `hwlab-dev``hwlab-g14-postgres` 和 PVC`hwlab-v02` namespace 还未成为独立运行面。v0.2 权限数据不能混用 `hwlab-dev` pgdata。
## 目标差距
| 领域 | 当前态 | 目标态 |
| --- | --- | --- |
| 用户 | 前端默认账号和本地 session fallback | Postgres `users` + `user_sessions``admin/user` 两角色 |
| Code Agent session | 内存 ownerless registry | `agent_sessions.owner_user_id` 持久归属,result/trace/cancel 按 owner 校验 |
| Device Pod | fake GET 数据,所有人可见;CLI 本地 profile 可决定 route | `device_pods.profile_json/profile_hash` 服务端权威 + `device_pod_grants` 授权过滤 |
| Device 操作 | 还不是正式 job/lease 权限入口 | cloud-api 授权后转发到 device-pod,独占操作用 `device_leases` |
| Cloud Web 路由 | 部分 agent route public | 除 health/static/login 外,用户态 API 都 auth-required |
| 微服务 | 没有用户服务 | 不新增用户服务,cloud-api 内置 user/auth/access 模块 |
| v0.2 数据面 | namespace/Postgres 目标未落地 | `hwlab-v02` 独立 namespace + 独立 Postgres DB/PVC/Secret |
## 迁移原则
- 不做 group/project/capability/read-operate 分级迁移;直接收敛到 `admin/user` 和 grant-exists-is-full-access。
- 不新增 user-management 微服务;先把用户管理做成 cloud-api 内部模块和 admin API。
- 不把 `audit_events` 复用成用户审计;保留它作为既有硬件证据链数据。
- 不把普通用户映射成 Kubernetes user/namespace/RBAC。
- 不为了兼容旧 public route 长期保留双路径;不兼容变更在同一阶段同步改后端、前端和测试。
- v0.2 数据面不复用 `hwlab-dev` pgdata;如需导入历史数据,显式写一次性迁移脚本并记录来源和目标。
## 推荐实施阶段
### 阶段 1Schema 和 bootstrap admin
新增 `0002_multi_user_access_v1` 迁移:
- 新增 `users``user_sessions``device_pods``device_pod_grants``device_leases`
- 扩展现有 `agent_sessions``owner_user_id``conversation_id``thread_id``last_trace_id``session_json``updated_at`
- 写入 bootstrap `admin`,密码只存 hash。
- 为 fake/default `device-pod-71-freq` 写入一条 `device_pods` 记录,并由 admin 导入 server-side `profile_json/profile_hash`,便于前端从 fake 数据迁到 DB 管理数据。
不兼容处理:已有 ownerless `agent_sessions` 不继续作为普通用户 session。迁移时一次性归属 bootstrap `admin` 或标记 `expired`,迁移后新 session 必须有 owner。
### 阶段 2cloud-api auth/access 模块
在 cloud-api 内新增模块:
- `authenticateRequest(request)`:从 cookie/session token 解析 actor。
- `requireActor(request)`:未登录返回 `401`
- `requireAdmin(actor)`:非 admin 返回 `403`
- `authorizeAgentSession(actor, sessionId|traceId|conversationId)`admin 或 owner。
- `authorizeDevicePod(actor, devicePodId)`admin 或存在 `device_pod_grants`
不兼容处理:除 `/health``/health/live`、静态资源和登录接口外,用户态 `/v1/*` 不再允许匿名访问。旧 public code agent poll route 直接改为 auth-required,不保留 legacy public mode。
### 阶段 3Cloud Web 登录和 admin UI
调整 cloud-web
- `/auth/session``/auth/login``/auth/logout` 代理或落到 cloud-api authority。
- 移除多用户运行态下的 local auth fallback;没有 server session 时显示登录页。
- 增加最小 admin UI:用户列表、创建/禁用用户、device pod 授权/撤销。
- 普通用户只显示自己的 code agent session 和被授权 device pod。
不兼容处理:默认 `admin/hwlab2026` 只能作为 bootstrap 初始化入口;完成初始化后应由管理员改密码或替换。前端测试 fixture 同步改成 server-session 模式。
### 阶段 4Code Agent session owner 持久化
调整 `/v1/agent/chat` 及相关路由:
- 创建或复用 session 时写入 `agent_sessions.owner_user_id`
- `conversation_id -> session_id` 绑定迁到 Postgres 或至少写入 session record。
- result/trace/cancel/inspect 根据 owner 校验。
- code agent prompt 中只暴露当前 actor 可见的 device pod 列表。
不兼容处理:部署前存在的浏览器本地 conversation/session 可能失效;前端应在 `401/403/session_expired` 时提示重新登录或新建会话,不做 ownerless session 兼容恢复。
### 阶段 5Device Pod 管理和授权过滤
调整 `/v1/device-pods`
- list/status 从 `device_pods` 读取管理数据,再按 actor 过滤。
- `admin` 可创建/更新/禁用 device pod。
- `admin` 是 profile authority,只能通过 cloud-api 创建/更新 `device_pods.profile_json`
- `admin` 可 upsert/delete `device_pod_grants`
- 未授权用户访问具体 device pod 返回 `403`
不兼容处理:普通用户不再默认看到 `device-pod-71-freq`。如果需要演示用户看到它,必须显式给该用户授权。code agent 本地 `.device-pod/*.json` 不再能改变正式 device pod route。
### 阶段 6Device jobs 和 lease
为真实设备操作增加 cloud-api job routes
- `POST /v1/device-pods/{devicePodId}/jobs`
- `GET /v1/device-pods/{devicePodId}/jobs/{jobId}`
- `POST /v1/device-pods/{devicePodId}/jobs/{jobId}/cancel`
cloud-api 先校验 actor 和 grant,再按操作类型获取 `device_leases`,最后转发到 `hwlab-device-pod` 内部 Service。
不兼容处理:device-pod 服务不面向普通用户直接暴露,不接受浏览器或 worker 直连作为授权依据,也不接受调用方上传 profile 作为执行依据;所有真实操作必须经过 cloud-api。
### 阶段 7v0.2 namespace 和数据面
部署面调整:
- 创建 `hwlab-v02` namespace。
- 建立 v0.2 独立 Postgres StatefulSet、Service、PVC 和 DB Secret。
- cloud-api v0.2 指向 v0.2 DB URL 和独立 migration ledger。
- Cloud Web/API FRP 使用 v0.2 规划入口 `19666/19667`
不兼容处理:不把 `hwlab-dev` 数据自动复制到 v0.2。需要保留的数据必须写明迁移对象、来源、目标和回滚方式;用户权限数据默认从 bootstrap admin 开始重建。
## 其他微服务调整
| 微服务 | 必要调整 |
| --- | --- |
| `hwlab-cloud-api` | 新增 user/auth/access 模块、admin API、session owner 校验、device grant/lease 校验。 |
| `hwlab-cloud-web` | 登录改为 server-session authority;增加 admin UI;普通用户视图按授权过滤。 |
| `hwlab-edge-proxy` | 保持透明转发,确保 cookie/header 不被丢弃;不注入业务 actor。 |
| `hwlab-agent-mgr` | session 创建参数和状态摘要带 `owner_user_id``session_id` label;不自行做最终授权。 |
| `hwlab-agent-worker` | Pod/Job/PVC label 带 owner/session,工具调用 device pod 时走 cloud-api。 |
| `hwlab-device-pod` | 从 fake GET 逐步扩展到多 `devicePodId` jobs API;信任 cloud-api 内部调用,不保存用户 grant,不接受用户上传 profile。 |
| `hwlab-agent-skills` | device-pod-cli 默认目标改为 cloud-api 授权 REST 入口,不直连 device-pod Service,不再以本地 profile 作为正式 route authority。 |
| GitOps/render | v0.2 增加 namespace、Postgres、SecretRef、ServiceAccount、PVC 和 env 注入。 |
## 最小验证
- 未登录访问 `/v1/agent/chat/result/*``/v1/agent/chat/trace/*``/v1/device-pods` 返回 `401`
- `admin` 能创建用户、创建设备、授权和撤销授权。
- 未授权 `user` 看不到 device pod,访问具体 device pod 返回 `403`
- 授权后 `user` 能看到并使用 device pod。
- `user A` 不能读取或取消 `user B` 的 code agent session。
- `admin` 可以跨用户查看和取消 session。
- 同一个 device pod 的独占操作只能被一个 active lease 持有。
- v0.2 cloud-api health 报告连接的是 v0.2 DB,不是 `hwlab-dev` pgdata。
+5 -5
View File
@@ -18,8 +18,8 @@ M3 virtual hardware trusted loop before broadening the product surface.
## Runtime Shape
The frozen service IDs live in [README.md](../../README.md). The runtime path
is:
Current service ownership and v0.2 keep/remove decisions are authoritative in
[spec-v02-services.md](spec-v02-services.md). The current G14 runtime path is:
```text
browser or CLI
@@ -90,6 +90,6 @@ Code Agent chat 证据单独分级:只有真实同源 `/v1/agent/chat`
board and priority status.
- [pikasTech/HWLAB#78](https://github.com/pikasTech/HWLAB/issues/78): M3
decision and prompt/review guardrails.
- [docs/operator-runbook.md](../operator-runbook.md): operator phase gates.
- [docs/dev-acceptance-matrix.md](../dev-acceptance-matrix.md): DEV acceptance
matrix and health contracts.
- [dev-runtime-boundary.md](dev-runtime-boundary.md): G14 DEV/PROD and v0.2 runtime boundary.
- [spec-v02-services.md](spec-v02-services.md): v0.2 microservice keep/remove and dependency boundary.
- [spec-v02-documentation-governance.md](spec-v02-documentation-governance.md): root README and legacy process document migration.
+2 -2
View File
@@ -273,7 +273,7 @@ blockers/failures`viewport`、`selector`、`failureType`、summary 和 artifa
resource explorer collapse and controlled resize feedback.
- [code-agent-chat-readiness.md](code-agent-chat-readiness.md): Code Agent
chat 同源 readiness 和 provider credential blocker 边界。
- [docs/cloud-web-workbench.md](../cloud-web-workbench.md): detailed frontend
contract.
- [spec-v02-services.md](spec-v02-services.md): Cloud Web runtime wrapper and browser-side TypeScript migration boundary.
- [pikasTech/HWLAB#532](https://github.com/pikasTech/HWLAB/issues/532): archived historical `docs/cloud-web-workbench.md` content.
- [g14-gitops-cicd.md](g14-gitops-cicd.md): Cloud Web rollout through G14 Tekton, GitOps and Argo CD
path.
+1 -1
View File
@@ -31,7 +31,7 @@
## 分支和交付工作流
- 单纯文档、CLI/helper 轻量变更默认直接提交并 push 到 `origin/G14`,不开 PR;这类变更仍要先从最新 `origin/G14` 创建独立 worktree,提交前审查 diff,只提交当前任务相关文件。
- `v0.2` 线的单纯文档和计划可以直接提交并 push 到 `origin/v0.2`,不开 PR;涉及 namespace 创建、Argo CD Application、Tekton poller/reconciler、FRP、Secret、DB、权限或 runtime rollout 的变更必须先有 `docs/plan/` 计划和 GitHub issue,再按计划分步执行
- `v0.2` 线的单纯文档和规格更新可以直接提交并 push 到 `origin/v0.2`,不开 PR;涉及 namespace 创建、Argo CD Application、Tekton poller/reconciler、FRP、Secret、DB、权限或 runtime rollout 的变更必须先有 GitHub issue 承接过程计划,再按 issue 和对应 `docs/reference/spec-*.md` 分步执行。仓库内不再新增 `docs/plan/*.md`
- 业务代码、运行面、发布链路、Secret、权限、数据迁移、PROD、重启服务、CI/CD 控制面高风险变更或其他影响 runtime truth 的变更默认走 PR 工作流。
- 用户或指挥官给出最新交付纠偏时,以最新要求为准,删除旧断言或旧门禁,不用 feature flag、legacy mode 或双路径长期并存绕开最新要求。
+2 -4
View File
@@ -449,10 +449,8 @@ M4, or M5 live evidence.
## Stable Sources
- [deploy/frp/README.md](../../deploy/frp/README.md): FRP DEV contract.
- [docs/d601-k3s-readonly-observability.md](../d601-k3s-readonly-observability.md):
read-only k3s visibility command.
- [docs/dev-acceptance-matrix.md](../dev-acceptance-matrix.md): DEV endpoint
and health acceptance.
- [spec-v02-cicd.md](spec-v02-cicd.md): v0.2 runtime namespace, FRP ports and GitOps lane boundary.
- [pikasTech/HWLAB#532](https://github.com/pikasTech/HWLAB/issues/532): archived legacy D601 observability and DEV acceptance root docs.
- [pikasTech/HWLAB#164](https://github.com/pikasTech/HWLAB/issues/164):
Code Agent provider and DB live hotfix follow-up contract.
- [pikasTech/HWLAB#61](https://github.com/pikasTech/HWLAB/issues/61): manual
+1 -1
View File
@@ -10,4 +10,4 @@
- v0.2 第一阶段使用一个 `hwlab-device-pod` Deployment/Service 管理多个逻辑 `devicePodId`,避免过早引入 per-device k8s workload 运维压力。
- 正式访问路径是 `device-pod-cli/cloud-web -> cloud-api -> hwlab-device-pod -> gateway -> device-host-cli -> target`
迁移计划见 [../plan/v02-device-pod-spec-migration.md](../plan/v02-device-pod-spec-migration.md)。历史 CLI MVP 闭环见 [../plan/device-pod-cli-mvp.md](../plan/device-pod-cli-mvp.md),但其中本地 profile 权威口径不适用于正式 v0.2 多用户接入。
实施跟踪见 [pikasTech/HWLAB#533](https://github.com/pikasTech/HWLAB/issues/533)。旧迁移计划和 CLI MVP 闭环全文已迁入该 issue 评论;其中本地 profile 权威口径不适用于正式 v0.2 多用户接入。
+5 -1
View File
@@ -2,12 +2,14 @@
本文是 HWLAB 仓库内固化的 `docs-spec` 规则副本和可执行摘要,也是本仓库唯一维护 `docs-spec` 使用规则的长期参考。它等价承担 `docs/reference/docs-spec.md` 的职责;不要再新增同级 `docs-spec` 规则副本,避免多处口径漂移。编辑 `AGENTS.md``docs/reference/*.md` 或把过程记录蒸馏为长期参考时,必须先按本文执行;如果 runner 能读取外部 `docs-spec` skill,也要以本文作为 HWLAB 本地权威落点。
`v0.2` 文档树的额外收敛规格见 [spec-v02-documentation-governance.md](spec-v02-documentation-governance.md)。该规格禁止仓库保留根 `README.md``docs/*.md``docs/*.json``docs/plan/*.md` 作为长期或过程文档入口;计划、里程碑和一次性记录必须迁入 GitHub issue。
中文优先规则只在 [chinese-first-documentation.md](chinese-first-documentation.md) 维护,用户和参谋反馈分流规则只在 [user-feedback-triage.md](user-feedback-triage.md) 维护。本文只交叉引用这些规则,不替代 [commander-collaboration.md](commander-collaboration.md) 中由 [pikasTech/HWLAB#131](https://github.com/pikasTech/HWLAB/issues/131) 固化的一手事实和真实推进边界。
## AGENTS.md 规则
- `AGENTS.md` 是 agent、指挥官和 runner 的唯一入口,用于快速定位命令、入口和长期参考文档。
- 与 `AGENTS.md` 同等作用的文档,例如 `README.md``docs/reference/README.md``CLAUDE.md`,不得作为入口或索引;如果必须存在,只能说明应回到 `AGENTS.md`,避免多套口径漂移
- 与 `AGENTS.md` 同等作用的文档,例如 `README.md``docs/reference/README.md``CLAUDE.md`,不得作为入口或索引;`v0.2` 不保留这类二级入口,历史内容迁入 issue 或吸收到对应 reference
- 每个命令在 `AGENTS.md` 中只保留一条主索引;参数、背景、判定标准写入链接的 reference 文档。
- `AGENTS.md` 的主标题、章节名和列表摘要必须中文优先;`Agent``runner``Cloud Workbench`、命令和路径等可保留原文,但要放在中文语境中解释。
- 每个列表项只描述一个功能点,用一句中文概括,不在顶层展开实现细节。
@@ -27,6 +29,7 @@
- 过程文档是历史资料,通常带时间戳,时效性强,不能直接进入长期参考。
- 蒸馏只提取稳定结论、边界、验收标准和禁止事项。
- 计划、plan、里程碑、阶段迁移、一次性报告和旧 gate 文档全文迁入 GitHub issue;仓库内不再维护 `docs/plan/*.md`
- 不篡改过程文档;过程记录是原始来源。
- 大文件按滑动窗口阅读,读一段就提炼稳定结论,不等全部读完才更新 reference。
- 新稳定结论覆盖旧冲突结论;旧过程只作为历史来源。
@@ -53,6 +56,7 @@
- `#121` 要求 issue 和长期文档中文化。
- `#122` 要求用户和参谋反馈默认高优先级并挂到 `#7`
- `#123` 要求 docs-spec 规则固化进 HWLAB 长期参考文档,而不是只在 issue 里引用外部 skill;本文就是该规则的等价本地文档。
- `#532``v0.2` 文档治理规格和被删除根文档/过程文档的全文归档入口;当前收敛规格见 [spec-v02-documentation-governance.md](spec-v02-documentation-governance.md)。
- 当前 HWLAB 的 G14 DEV `17666/17667`、G14 PROD `18666/18667`、G14 工作区、M3 证据、Cloud Workbench 默认路由和 PR 工作流,分别由本目录的专项 reference 维护;D601 只作为 legacy 迁移/事故回放口径维护。
## docs-spec 原文副本
+2
View File
@@ -2,6 +2,8 @@
本文是 HWLAB `v0.2` 正式接入 `device-pod` 的规格说明。`device-pod` 是一个逻辑设备能力单元,不是 Kubernetes Pod 名称,也不是 code agent 本地 profile 文件。正式接入后,profile 定义 `device-pod`,因此 profile 必须由管理员和服务端权威存储管理,不能由 code agent 本地文件决定路由或资源边界。
实施跟踪见 [pikasTech/HWLAB#533](https://github.com/pikasTech/HWLAB/issues/533),原 `docs/plan/v02-device-pod-spec-migration.md` 和旧 device-pod MVP 计划全文已迁入该 issue 评论。
旧的 `device-pod-cli` 本地 profile 闭环只用于 CLI MVP 和真实硬件最小验证。进入正式多用户系统后,所有用户态设备访问必须收敛到:
```text
+3 -2
View File
@@ -4,6 +4,8 @@
本规格与 [spec-device-pod.md](spec-device-pod.md) 配套:用户和权限规格定义谁可以看见、创建和使用 device poddevice-pod 规格定义 profile authority、REST/job 和硬件执行边界。
实施跟踪见 [pikasTech/HWLAB#531](https://github.com/pikasTech/HWLAB/issues/531),原 `docs/plan/v02-multi-user-migration.md` 迁移计划全文已迁入该 issue 评论。
## 在系统中的职责划分
用户和权限管理不是独立微服务,权威实现收敛在 `hwlab-cloud-api`:它负责登录、session、角色、device pod grant、device lease 和 code agent session owner 校验。`hwlab-cloud-web` 只提供浏览器 UI 和同源代理;`hwlab-device-pod` 只执行设备语义;`hwlab-agent-mgr``hwlab-agent-worker` 和 Code Agent runtime 只能消费已经由 cloud-api 判断过的 actor/session/device 权限。
@@ -307,7 +309,7 @@ Kubernetes 只做运行时隔离和资源兜底,不承载 HWLAB 用户权限
- code agent 到 device pod 的访问应收敛到 `code agent -> cloud-api -> device-pod`,避免普通 session Pod 直接调用 device pod Service 绕过应用层授权。
- 第一轮不引入 Keycloak、Dex、oauth2-proxy、OpenFGA、Capsule、vCluster、Kyverno 或 service mesh;需要正式外部身份源或集群 admission 兜底时再单独设计。
当前态、差距和迁移步骤见 [../plan/v02-multi-user-migration.md](../plan/v02-multi-user-migration.md)
当前态、差距和迁移步骤已迁入 [pikasTech/HWLAB#531](https://github.com/pikasTech/HWLAB/issues/531) 评论
## 测试规格
@@ -332,4 +334,3 @@ Kubernetes 只做运行时隔离和资源兜底,不承载 HWLAB 用户权限
| Code Agent owner 绑定 | 未完全实现 | `agent_sessions` 已存在,owner 字段和鉴权链路仍需落地。 |
| device pod 授权模型 | 未完全实现 | grant 语义已定义;当前 device-pod 仍主要是 fake/只读 payload。 |
| 不用 Kubernetes 表达用户权限 | 已实现/持续约束 | 规格明确禁止普通用户持有 kubeconfig 或直连 Service 权限。 |
+3 -3
View File
@@ -2,7 +2,7 @@
本文是 HWLAB `v0.2` 在 G14 上接入 CI/CD 的长期规格。目标是把 `v0.2` 作为独立加法 lane 接入现有 G14 k3s、Tekton、GitOps 和 Argo CD 体系,同时保持 `G14` DEV/PROD 发布面稳定。
实施跟踪见 [pikasTech/HWLAB#530](https://github.com/pikasTech/HWLAB/issues/530)阶段计划见 [../plan/hwlab-v02-namespace-cicd.md](../plan/hwlab-v02-namespace-cicd.md)。本文只记录稳定规格、边界和判定标准;不要把一次性执行记录、排障流水账或临时证据写入本文。
实施跟踪见 [pikasTech/HWLAB#530](https://github.com/pikasTech/HWLAB/issues/530)`docs/plan/hwlab-v02-namespace-cicd.md` 阶段计划全文已迁入该 issue 评论。本文只记录稳定规格、边界和判定标准;不要把一次性执行记录、排障流水账或临时证据写入本文。
## 在系统中的职责划分
@@ -69,7 +69,7 @@ CI/CD 内部由 branch poller、PipelineRun、component planner、BuildKit publi
`v0.2` source branch 可以包含:
- 源码、测试、文档人写计划
- 源码、测试、文档人写配置和模板
- `deploy/deploy.json` 或等价 lane 配置。
- k8s 模板、render 脚本、CI/CD helper 和 catalog schema。
@@ -195,7 +195,7 @@ GitOps branch 已更新、source branch render 通过、PipelineRun 名称存在
## 平行 lane 运维边界
后续新增 `v0.x` 或其他平行 runtime lane 时,优先复用本节的判定顺序和排障边界,避免把一次性补丁沉淀成新的宽泛门禁。本节只保留可复用的运维边界;具体执行记录、排障流水和一次性证据应放在 issue、PR 或 `docs/plan/` 中。
后续新增 `v0.x` 或其他平行 runtime lane 时,优先复用本节的判定顺序和排障边界,避免把一次性补丁沉淀成新的宽泛门禁。本节只保留可复用的运维边界;具体执行记录、排障流水和一次性证据应放在 issue 或 PR 中。
### Secret 导入与重启边界
@@ -0,0 +1,64 @@
# v0.2 文档治理规格
本文是 HWLAB `v0.2` 文档体系的长期规格。它定义哪些文档可以留在仓库、哪些过程材料必须迁入 GitHub issue、旧 D601/G14 口径如何处理,以及 `docs/` 根目录不得再堆放 Markdown 或 JSON 的收敛规则。
实施和历史归档见 [pikasTech/HWLAB#532](https://github.com/pikasTech/HWLAB/issues/532)。本文只记录稳定规则;被迁移文档的全文在 issue 评论中按源路径归档。
## 设计目标
- `AGENTS.md` 是唯一顶级入口;不再维护根 `README.md``docs/reference/README.md`
- `docs/reference/` 是长期参考唯一目录,只放规格、约束、入口、判定标准和稳定 runbook。
- `v0.2` 专项长期规格必须使用 `spec-` 前缀,例如 `spec-v02-cicd.md``spec-user-access.md`
- 计划、里程碑、阶段推进、一次性排障、报告合同和历史验收材料不留在仓库文档树;全文迁入 GitHub issue 后删除源 Markdown。
- `docs/` 根目录不得直接放 `*.md``*.json`。机器契约放 `protocol/``deploy/` 或源码相邻目录;临时报告放 `/tmp``.state` 或 CI artifact。
- D601、旧 DEV gate、旧 `16666/16667`、M0-M5 里程碑和 simulator/patch-panel 旧规格只作为历史归档,不作为 `v0.2` 当前规格。
## 允许的文档形态
| 位置 | 允许内容 | 不允许内容 |
| --- | --- | --- |
| `AGENTS.md` | 入口索引、一句话规则、长期参考链接 | 详细设计、计划全文、过程记录、二级 README 口径 |
| `docs/reference/*.md` | 长期规格、稳定边界、判定标准、可复用 runbook | 日期化流水账、阶段计划、迁移 TODO 全文、临时 evidence、旧规格副本 |
| GitHub issue/PR | 计划全文、里程碑拆解、过程记录、一次性排障、执行证据 | 作为长期权威替代 `docs/reference` |
| `protocol/` / `deploy/` | 机器可消费 schema、deploy intent、GitOps 模板 | 人写过程报告、临时 JSON dump |
| `/tmp` / `.state` / CI artifact | 临时报告、运行输出、截图、trace dump | 需要长期复用的规格 |
## 迁移规则
1. 发现 `README.md``docs/*.md``docs/*.json``docs/plan/*.md` 时,先判断是否有长期价值。
2. 有长期价值的,只把稳定结论吸收到对应 `docs/reference/` 权威文档;不要整篇搬入 reference。
3. 属于计划、里程碑、阶段迁移、报告、一次性排障或历史验收的,全文迁入 GitHub issue body/comment,再删除源文件。
4. 属于旧规格且与当前 `v0.2` spec 冲突的,直接删除;必要时在新 spec 中用一句话说明旧口径已被替代。
5. 迁移后的 reference 必须引用相关 issue,尤其是规格尚未完全实现、仍需要 issue 承接实施步骤时。
6. GitHub issue/PR 写入必须走 UniDesk CLI `bun scripts/cli.ts gh ...`,不能直接用原生 `gh` 或手写 GitHub API。
## D601/G14 口径处理
- 当前 HWLAB DEV/PROD 真相是 G14 k3s、`G14`/`G14-gitops``hwlab-dev`/`hwlab-prod`
- `v0.2` 真相是 `origin/v0.2``v0.2-gitops``hwlab-v02``19666/19667`,权威规格见 [spec-v02-cicd.md](spec-v02-cicd.md)。
- D601 只允许作为 legacy 事故回放、迁移对照或 Windows 硬件 bridge 背景出现在长期参考中;不得作为当前 `v0.2` 发布、验收或权限规格。
- 任何根文档或计划文档如果仍把 D601、旧 DEV gate、旧 `main`、旧 `16666/16667` 或 simulator/patch-panel 写成当前规格,应删除或改为引用新 spec。
## 本次收敛映射
| 被删除来源 | 处理 |
| --- | --- |
| `README.md` | 有效入口信息已由 `AGENTS.md`、[architecture.md](architecture.md)、[dev-runtime-boundary.md](dev-runtime-boundary.md) 和 [spec-v02-services.md](spec-v02-services.md) 承接;全文归档到 #532。 |
| `docs/cloud-web-workbench.md` | 稳定前端约束由 [cloud-workbench.md](cloud-workbench.md) 承接;全文归档到 #532。 |
| `docs/dev-acceptance-matrix.md``docs/dev-gate-*``docs/dev-evidence-*` | 旧 DEV/D601 gate 和报告材料仅作历史归档;当前边界见 [dev-runtime-boundary.md](dev-runtime-boundary.md)、[MVP-e2e-acceptance.md](MVP-e2e-acceptance.md) 和 [spec-v02-cicd.md](spec-v02-cicd.md)。 |
| `docs/dev-acceptance-checklist.json` | 从 `docs/` 根目录移出;仍被旧 M5 dry-run 使用的机器 fixture 放到 `fixtures/mvp/m5-e2e/dev-acceptance-checklist.json`,历史全文归档到 #532。 |
| `docs/m0-*``docs/m1-*``docs/m3-*``docs/m4-*``docs/m5-*``docs/operator-runbook.md` | 旧里程碑和 operator 阶段材料迁入 #532;当前 M3 判定见 [m3-loop-rollout-runbook.md](m3-loop-rollout-runbook.md)。 |
| `docs/topology-constraints.md` | simulator/patch-panel 旧拓扑规格与 `v0.2` 裁撤口径冲突;当前服务取舍见 [spec-v02-services.md](spec-v02-services.md)。 |
| `docs/schema-drift-map.md` | 人写摘要归档到 #532;机器 source of truth 仍是 `protocol/schema-drift-map.json`。 |
| `docs/plan/hwlab-v02-namespace-cicd.md` | 全文迁入 [pikasTech/HWLAB#530](https://github.com/pikasTech/HWLAB/issues/530) 评论;长期规格见 [spec-v02-cicd.md](spec-v02-cicd.md)。 |
| `docs/plan/v02-multi-user-migration.md` | 全文迁入 [pikasTech/HWLAB#531](https://github.com/pikasTech/HWLAB/issues/531) 评论;长期规格见 [spec-user-access.md](spec-user-access.md)。 |
| `docs/plan/v02-device-pod-spec-migration.md` 和旧 device-pod MVP plan | 全文迁入 [pikasTech/HWLAB#533](https://github.com/pikasTech/HWLAB/issues/533) 评论;长期规格见 [spec-device-pod.md](spec-device-pod.md)。 |
## 验收标准
- `AGENTS.md` 索引本文,并且不再把 `README.md` 当入口。
- `find docs -maxdepth 1 -type f \( -name '*.md' -o -name '*.json' \)` 为空。
- `docs/plan` 不再包含仓库内计划 Markdown;后续计划写入 GitHub issue。
- `docs/reference/` 中不存在指向已删除根文档或 `docs/plan` 的相对链接。
- `D601` 只以 legacy/回放/bridge 背景出现在长期参考;不会作为 `v0.2` 当前规格或验收路径。
- 任何未完成规格都必须引用承接实施的 GitHub issue。
-60
View File
@@ -1,60 +0,0 @@
# HWLAB Runtime Boundary Guard
The HWLAB runtime may use UniDesk CI/CD infrastructure and Code Queue
scheduling, but it must not use UniDesk backend, provider-gateway, or
microservice proxy as replacement runtime services. Those systems are external
supporting infrastructure only.
This guard is intentionally static. It reads repository files and does not
contact the DEV endpoint, deploy to DEV or PROD, read secrets, or restart any
UniDesk or HWLAB runtime process.
## Boundary Rule
- 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:16667`.
- The DEV namespace is `hwlab-dev`.
- PROD deployment and PROD acceptance remain disabled.
- UniDesk backend, provider-gateway, and microservice proxy are forbidden
runtime substitutes.
UniDesk may remain in the control-plane path for CI, CD, and Code Queue
scheduling. It must not terminate HWLAB health, API, gateway, router, tunnel,
agent, simulator, patch-panel, CLI, or skills runtime contracts on behalf of
HWLAB.
## Checked Artifacts
The machine-readable fixture is
`protocol/examples/runtime-boundary/guard.dev.json`. It records the expected
DEV-only boundary, frozen service IDs, forbidden substitutes, and paths checked
by `scripts/validate-runtime-boundary.mjs`.
The validator checks:
- `deploy/deploy.json` keeps `environment: dev`, `hwlab-dev`, the fixed DEV
endpoint, the complete HWLAB service set, HWLAB image names, and a disabled
PROD profile.
- `deploy/master-edge/health-contract.json` keeps the `frp` D601-to-master
reverse link, HWLAB contract service IDs, and the forbidden substitute list.
- `deploy/k8s/base/workloads.yaml` keeps workload names, labels, container
names, and images under HWLAB service IDs.
- `deploy/k8s/base/services.yaml` keeps Kubernetes service names and labels
under HWLAB service IDs.
- `deploy/k8s/dev/*` keeps the DEV overlay and runtime substitute policy.
- `deploy/k8s/prod/*` keeps PROD as a disabled placeholder only.
## Validation
Run:
```sh
node --check scripts/validate-runtime-boundary.mjs
node scripts/validate-runtime-boundary.mjs
```
The script is lightweight and has no package dependency. It fails if a checked
artifact drifts toward a UniDesk runtime substitute, a non-DEV environment, an
unexpected namespace, an unexpected endpoint, or an incomplete HWLAB service
boundary.
-83
View File
@@ -1,83 +0,0 @@
# Schema Drift Map
This document records the naming drift between the protocol schemas, the L1
cloud-core migration skeleton, the audit chain, the evidence chain, and the
deploy manifest example. It is a closure artifact for M0 audit work only.
## Scope
- protocol: `protocol/schemas/*.json`
- DB migration: `internal/db/migrations/0001_cloud_core_skeleton.sql`
- audit event: `protocol/schemas/audit-event.schema.json`
- evidence chain: `protocol/evidence-chain.md`
- evidence record: `protocol/schemas/evidence-record.schema.json`
- deploy manifest: `deploy/deploy.json`
- deploy schema: `deploy/deploy.schema.json`
The source of truth for machine checks is `protocol/schema-drift-map.json`.
This page is the human summary.
## Aligned Fields
The following IDs are already aligned at the protocol layer and are carried
through the current examples:
- `projectId`
- `operationId`
- `auditId`
- `traceId`
- `evidenceId`
- `serviceId`
- `environment`
- `resourceId`
- `sessionId` family: `gatewaySessionId`, `agentSessionId`, `workerSessionId`
- evidence chain roots: `chainId`, `schemaVersion`, `scenario`, `title`
- evidence chain collections: `hardwareOperation`, `auditEvents`, `traceEvents`, `evidenceRecords`
## Known Gaps
These are the places where the L1 skeleton still drifts from protocol naming
and needs a real persistence fix before production data is written:
- `audit_events.request_id` should become `traceId`
- `audit_events.actor` should split into `actorType` and `actorId`
- `audit_events.source` should become `actorId`
- `audit_events.operation` should become `action`
- `audit_events.target` should split into `targetType` and `targetId`
- `audit_events.timestamp` should become `occurredAt`
- `evidence_records.evidence_type` should become `kind`
- `evidence_records.metadata_json.sha256` needs a first-class persisted target
- `hardware_operations.operation_json.resourceId` needs a tested mapping path
- `hardware_operations.operation_json.capabilityId` needs a tested mapping path
## Evidence Chain
The evidence chain fixture set is already internally coherent. It binds the
root IDs to the protocol schemas without changing the storage model:
- `chainId` anchors the fixture
- `operationId` ties hardware, audit, trace, and evidence together
- `traceId` threads through audit and trace events and is copied into evidence
metadata
- `gatewaySessionId`, `agentSessionId`, and `workerSessionId` stay consistent
where they appear
- `hardwareOperation`, `auditEvents`, `traceEvents`, and `evidenceRecords`
each point back to their schema counterparts
## Impact
The current examples and validators are sufficient for audit evidence and MVP
closure, but they are not a persistence contract. The drift map is intentionally
read-only so later implementation work can pick one of two paths:
1. rename the real storage columns to match the protocol, or
2. keep the current skeleton and add a tested mapping layer before writes.
## Validation
Run:
```sh
node --check scripts/validate-schema-drift-map.mjs
node scripts/validate-schema-drift-map.mjs
```
-46
View File
@@ -1,46 +0,0 @@
# Topology Constraint Validator
`scripts/validate-topology-constraints.mjs` is a local contract validator for
the MVP topology rules that were prose-only after M0. It reads fixtures from
`fixtures/mvp/topology-constraints/` and does not call DEV, PROD, real
hardware, databases, secrets, or service endpoints.
Run it locally:
```sh
node scripts/validate-topology-constraints.mjs
```
## Contract
- The fixture must describe a DEV topology with `hwlab-box-simu`,
`hwlab-gateway-simu`, and one active `hwlab-patch-panel` status object.
- Cross-device propagation must remain `patch-panel-only`. Box simulator local
loopback is not a valid substitute for cross-device sync.
- Wiring endpoints must reference known box resources and declared ports.
- Active wiring configs must not contain resource-level directed cycles.
- Active config exclusivity is enforced per project and resource group. The
resource group is `wiringConfig.constraints.resourceGroupId` when present;
otherwise it is the sorted set of resources touched by the config.
- A resource group may have only one active wiring config unless the active
patch panel reports `metadata.activeConfigOverride`.
- A patch-panel override is valid only when it is reported by an active
`hwlab-patch-panel`, preserves `patch-panel-only`, lists exactly the active
config ids for the resource group, gives a non-empty reason, and selects the
same `wiringConfigId` as the patch panel status object.
- The patch panel's `activeConnections` must match the selected wiring config.
## Fixtures
| Fixture | Expected result | Purpose |
| --- | --- | --- |
| `valid-topology.json` | valid | One active acyclic config routed by `hwlab-patch-panel`. |
| `invalid-cycle.json` | `wiring_cycle` | Detects a directed resource cycle in active wiring. |
| `invalid-multiple-active-configs.json` | `active_config_exclusivity` | Rejects multiple active configs in the same resource group without an override. |
| `invalid-patch-panel-override.json` | `patch_panel_override_invalid` | Rejects a patch-panel override whose selected config disagrees with patch panel state. |
Each fixture stores `expectedValidation` beside the topology. The validator
passes only when valid fixtures produce no violations and invalid fixtures
produce the expected violation code set. This makes the validator a pre-DEV
contract for the future real M3 flow while keeping the current M3 hardware loop
smoke focused on local patch-panel behavior.
@@ -1,6 +1,6 @@
{
"$schema": "https://hwlab.pikastech.local/docs/dev-acceptance-checklist.schema.json",
"$id": "https://hwlab.pikastech.local/docs/dev-acceptance-checklist.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",
@@ -434,7 +434,7 @@
{
"id": "static-contract-parse",
"order": 1,
"probe": "Parse docs/dev-acceptance-checklist.json and confirm docs/dev-acceptance-matrix.md exists.",
"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"
+2 -2
View File
@@ -13,8 +13,8 @@
"allowSecrets": false,
"allowedSourceGlobs": [
"protocol/**",
"docs/dev-acceptance-checklist.json",
"docs/dev-acceptance-matrix.md",
"fixtures/mvp/m5-e2e/dev-acceptance-checklist.json",
"docs/reference/MVP-e2e-acceptance.md",
"fixtures/mvp/runtime.json",
"fixtures/mvp/m5-e2e/**"
],
+6 -12
View File
@@ -83,18 +83,12 @@ function defaultMvpGateReport() {
sourceContract: {
status: "pass",
documents: [
"docs/dev-gate-report.md",
"docs/dev-acceptance-matrix.md",
"docs/m0-contract-audit.md",
"docs/m1-local-smoke.md",
"docs/m2-dev-deploy-smoke.md",
"docs/m3-hardware-loop.md",
"docs/m4-agent-loop.md",
"docs/m5-mvp-e2e.md",
"docs/runtime-boundary-guard.md",
"docs/topology-constraints.md",
"docs/artifact-catalog.md",
"docs/schema-drift-map.md",
"docs/reference/MVP-e2e-acceptance.md",
"docs/reference/m3-loop-rollout-runbook.md",
"docs/reference/dev-runtime-boundary.md",
"docs/reference/spec-v02-documentation-governance.md",
"docs/reference/g14-gitops-cicd.md",
"docs/reference/spec-v02-services.md",
"protocol/README.md",
"protocol/audit.md",
"protocol/evidence-chain.md",
@@ -49,6 +49,14 @@
"profile": "dev",
"replicas": 1
},
{
"serviceId": "hwlab-device-pod",
"image": "ghcr.io/pikastech/hwlab-device-pod:6509a35",
"namespace": "hwlab-dev",
"healthPath": "/healthz",
"profile": "dev",
"replicas": 1
},
{
"serviceId": "hwlab-gateway",
"image": "ghcr.io/pikastech/hwlab-gateway:6509a35",
@@ -6,6 +6,7 @@
"hwlab-cloud-web",
"hwlab-agent-mgr",
"hwlab-agent-worker",
"hwlab-device-pod",
"hwlab-gateway",
"hwlab-gateway-simu",
"hwlab-box-simu",
+3 -4
View File
@@ -1972,11 +1972,10 @@ function createReport({ args, repo, commitId, shortCommit, mode, services, artif
sourceContract: {
status: fatalBlocked ? "blocked" : "pass",
documents: [
"docs/dev-acceptance-matrix.md",
"docs/m0-contract-audit.md",
"docs/artifact-catalog.md",
"docs/reference/MVP-e2e-acceptance.md",
"docs/reference/spec-v02-documentation-governance.md",
"docs/reference/g14-gitops-cicd.md",
"docs/dev-base-image-preflight.md"
"docs/reference/spec-v02-cicd.md"
],
summary: `${environment} artifact publish evidence; runtime acceptance stays separate from artifact publication.`
},
+6 -6
View File
@@ -1415,8 +1415,8 @@ function baseReport({ commitId, observedAt }) {
sourceContract: {
status: "pass",
documents: [
"docs/dev-acceptance-matrix.md",
"docs/m3-hardware-loop.md",
"docs/reference/MVP-e2e-acceptance.md",
"docs/reference/m3-loop-rollout-runbook.md",
"fixtures/mvp/m3-hardware-loop/topology.json"
],
summary: "Source contracts define DEV-only M3 simulator wiring and prohibit fixture output as live evidence."
@@ -1463,8 +1463,8 @@ function baseReport({ commitId, observedAt }) {
status: "pass",
summary: "DEV M3 smoke contract files were readable before live probing.",
evidence: [
"docs/dev-acceptance-matrix.md",
"docs/m3-hardware-loop.md"
"docs/reference/MVP-e2e-acceptance.md",
"docs/reference/m3-loop-rollout-runbook.md"
]
},
{
@@ -1611,8 +1611,8 @@ function addNotRunM3Checks(report, reason) {
}
async function ensureContractFiles() {
await access(path.join(repoRoot, "docs/dev-acceptance-matrix.md"));
await access(path.join(repoRoot, "docs/m3-hardware-loop.md"));
await access(path.join(repoRoot, "docs/reference/MVP-e2e-acceptance.md"));
await access(path.join(repoRoot, "docs/reference/m3-loop-rollout-runbook.md"));
await access(path.join(repoRoot, "fixtures/mvp/m3-hardware-loop/topology.json"));
}
+1 -1
View File
@@ -35,7 +35,7 @@ import {
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const fixedNow = () => "2026-05-22T00:00:00.000Z";
const requiredDocs = ["docs/dev-acceptance-matrix.md", "docs/dev-m4-agent-loop.md"];
const requiredDocs = ["docs/reference/MVP-e2e-acceptance.md", "docs/reference/code-agent-chat-readiness.md"];
const reportPath = tempReportPath("dev-m4-agent-loop.json");
const preflightCommand = "node scripts/dev-m4-agent-loop-smoke.mjs --live --confirm-dev --confirmed-non-production";
const dryRunCommand = "node scripts/dev-m4-agent-loop-smoke.mjs --dry-run";
+3 -3
View File
@@ -9,8 +9,8 @@ import { DEV_ENDPOINT, ENVIRONMENT_DEV } from "../internal/protocol/index.mjs";
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const planPath = "fixtures/mvp/m5-e2e/dry-run-plan.json";
const checklistPath = "docs/dev-acceptance-checklist.json";
const matrixPath = "docs/dev-acceptance-matrix.md";
const checklistPath = "fixtures/mvp/m5-e2e/dev-acceptance-checklist.json";
const matrixPath = "docs/reference/MVP-e2e-acceptance.md";
const runtimePath = "fixtures/mvp/runtime.json";
const contractPath = "protocol/mvp-e2e-contract.md";
const commonSchemaPath = "protocol/schemas/common.json";
@@ -598,7 +598,7 @@ const [plan, checklist, runtime, contract, matrix, commonSchema] = await Promise
serviceIds = commonSchema.$defs.serviceId.enum;
serviceIdSet = new Set(serviceIds);
assert.equal(matrix.includes("HWLAB DEV Acceptance Matrix"), true, "acceptance matrix exists");
assert.equal(matrix.includes("HWLAB MVP E2E"), true, "MVP E2E reference exists");
assertObjectHasOnlyDryRunSafety(plan);
assertEndpointFreeze(plan, checklist, runtime, contract);
const artifacts = assertArtifacts(plan, checklist);
@@ -1384,7 +1384,6 @@ function layoutSourceContract() {
return {
status: "pass",
documents: [
"docs/cloud-web-workbench.md",
"docs/reference/cloud-workbench.md",
"docs/reference/code-agent-chat-readiness.md"
],
@@ -1518,7 +1517,6 @@ function baseReport({
sourceContract: {
status: "pass",
documents: [
"docs/cloud-web-workbench.md",
"docs/reference/cloud-workbench.md",
"docs/reference/code-agent-chat-readiness.md"
],
@@ -2704,8 +2702,7 @@ function findHelpMarkdownFiles() {
"web/hwlab-cloud-web/help.md",
"web/hwlab-cloud-web/help/README.md",
"web/hwlab-cloud-web/help/index.md",
"docs/dev-cloud-workbench-help.md",
"docs/cloud-web-workbench.md"
"docs/reference/cloud-workbench.md"
];
return files.filter((relativePath) => fs.existsSync(path.join(repoRoot, relativePath)));
}
+3 -3
View File
@@ -165,9 +165,9 @@ async function createDevGateReport(edgeHealth) {
sourceContract: {
status: "pass",
documents: [
"docs/dev-acceptance-matrix.md",
"docs/m0-contract-audit.md",
"docs/dev-edge-health.md",
"docs/reference/dev-runtime-boundary.md",
"docs/reference/spec-v02-documentation-governance.md",
"docs/reference/g14-gitops-cicd.md",
"deploy/frp/README.md",
"deploy/master-edge/README.md"
],
@@ -307,7 +307,7 @@ function buildEvidence() {
category: "contract",
level: "SOURCE",
status: "pass",
sources: ["protocol/README.md", "docs/dev-acceptance-matrix.md"],
sources: ["protocol/README.md", "docs/reference/MVP-e2e-acceptance.md"],
commands: ["node scripts/validate-contract.mjs"],
summary: "Frozen contracts remain the source-ready baseline."
}),
+5 -8
View File
@@ -14,7 +14,7 @@ import {
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const examplesDir = "protocol/examples/m0-contract";
const auditDocPath = "docs/m0-contract-audit.md";
const auditDocPath = "docs/reference/spec-v02-documentation-governance.md";
const timestampPattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
const idPattern = /^[a-z][a-z0-9]*_[A-Za-z0-9._:-]+$/;
@@ -226,16 +226,13 @@ function assertDeployManifest(doc) {
async function assertAuditMarkdown() {
const doc = await readFile(path.join(repoRoot, auditDocPath), "utf8");
for (const needle of [
"# M0 Contract Audit",
"## Audit Result",
"## Coverage Matrix",
"## Rework Risk Register",
"## Validation"
"# v0.2 文档治理规格",
"docs/m0-*",
"旧里程碑",
"#532"
]) {
assert.ok(doc.includes(needle), `${auditDocPath} missing ${needle}`);
}
assert.ok(doc.includes("Blocker"), `${auditDocPath} must classify blocker risks`);
assert.ok(doc.includes("Enhancement"), `${auditDocPath} must classify enhancement risks`);
}
const examples = await loadExamples();