docs: consolidate v0.2 documentation governance
This commit is contained in:
@@ -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 branch,G14 默认 `origin/G14`,`v0.2` 默认 `origin/v0.2`;业务代码、运行面、发布链路、Secret、权限、数据迁移、PROD 或其他高风险变更走 PR 工作流,详见 [docs/reference/commander-collaboration.md](docs/reference/commander-collaboration.md)。
|
||||
|
||||
## 常用轻量命令
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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、串口或下载器 smoke;Keil、串口监控、mklink 和文件编辑 skill 只能作为实现参考,不作为运行时依赖。D518 侧只承载硬件上位机逻辑,不改变 G14 source truth。
|
||||
5. 在 G14 code agent pod 中开发和验证 `device-pod-cli`,code agent pod 不放完整 HWLAB 源码和 Git key;CLI 通过 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 用于本地和 CI;live 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/evidence;live smoke 至少证明一次真实 debug probe 路径可达。
|
||||
- `io-probe:/uart/1 read` 与 `io-probe:/inner/... read` 在输出中明确标注外部/内部来源,不互相冒充。
|
||||
- gateway 仍只是 cmd transport;CLI 不暴露任意 shell、不接收泛化 `cmd` 子命令、不绕过 profile 访问硬件。
|
||||
- 文档、CLI 帮助和 skill 说明明确写明该 CLI 只用于 HWLAB 内部 code agent,不适用于 UniDesk 外部开发者工作区。
|
||||
@@ -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 proxy;upstream 不可用或未配置时回退到 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 前端拓扑。
|
||||
@@ -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 entry:Cloud 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 path;catalog 缺失只能触发 `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/namespace,promote 断言 GitOps branch/changed paths,Argo 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 commitId,runtime manifest 使用 digest pin;lane 身份记录在 catalog 和 runtime annotation。不要把 lane-specific 配置 bake 进镜像。 |
|
||||
| 清理任务误删 | stale PipelineRun cleanup、registry GC 或 Argo prune 误触 G14 DEV/PROD。 | 初期不新增自动 registry GC;如后续启用 cleanup,selector 必须带 lane label,registry GC 保护集取 `G14-gitops` 与 `v0.2-gitops` 的 digest union。 |
|
||||
| 并发资源争抢 | 两个分支同时 build,G14 DEV rollout 变慢。 | `v0.2` 初期使用较低 poller 频率或手动触发;设置 Pipeline resources requests/limits;G14 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 commitId;runtime 以 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 + 独立 database;PVC 独立;如后续选择 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/memory,G14 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` 读取上一版 catalog;catalog 缺失时只能执行 `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 state;build/publish helper 可复用现有工具镜像、registry 和 BuildKit 机制,但产物 catalog、GitOps branch、runtime path 必须隔离。
|
||||
- 镜像 tag 使用完整 source commitId,最终部署 identity 以 digest pin 为准。
|
||||
|
||||
5. Argo CD 扩容
|
||||
- 新增 `hwlab-g14-v02` Application,source 指向 `v0.2` 专属 GitOps lane,destination 指向 `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 intent;image 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 health,payload 的 namespace、revision 或 runtime identity 能和 `v0.2` lane 对齐。
|
||||
|
||||
## 回滚边界
|
||||
|
||||
`v0.2` 是新增运行面。若接入失败,回滚应只删除或暂停 `hwlab-v02` lane 的新增 Application、poller、reconciler、runtime path、FRP 入口或 namespace 资源;不得回滚、删除或重启现有 `hwlab-dev` / `hwlab-prod` 运行面。
|
||||
@@ -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 proxy;upstream 不可用时回退 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 标为 live;fake 只用于 UI/fixture/降级展示。
|
||||
|
||||
## 阶段 1:Schema 收口
|
||||
|
||||
在多用户迁移中同步调整 `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。
|
||||
|
||||
## 阶段 2:cloud-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。
|
||||
|
||||
## 阶段 3:hwlab-device-pod 多设备服务
|
||||
|
||||
把 `cmd/hwlab-device-pod/main.mjs` 从 fake GET 改造成正式服务:
|
||||
|
||||
- 维护内存 registry:`devicePodId -> profileHash/status/freshness/jobs`。
|
||||
- 提供内部 REST:status、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`。
|
||||
|
||||
## 阶段 4:device-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 本地文件。
|
||||
|
||||
## 阶段 6:Cloud 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 判定。
|
||||
|
||||
## 阶段 7:v0.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 证据。
|
||||
@@ -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;如需导入历史数据,显式写一次性迁移脚本并记录来源和目标。
|
||||
|
||||
## 推荐实施阶段
|
||||
|
||||
### 阶段 1:Schema 和 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。
|
||||
|
||||
### 阶段 2:cloud-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。
|
||||
|
||||
### 阶段 3:Cloud 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 模式。
|
||||
|
||||
### 阶段 4:Code 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 兼容恢复。
|
||||
|
||||
### 阶段 5:Device 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。
|
||||
|
||||
### 阶段 6:Device 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。
|
||||
|
||||
### 阶段 7:v0.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。
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 或双路径长期并存绕开最新要求。
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 多用户接入。
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
本规格与 [spec-device-pod.md](spec-device-pod.md) 配套:用户和权限规格定义谁可以看见、创建和使用 device pod;device-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 权限。 |
|
||||
|
||||
|
||||
@@ -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。
|
||||
@@ -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.
|
||||
@@ -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
|
||||
```
|
||||
@@ -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.
|
||||
+3
-3
@@ -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"
|
||||
@@ -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/**"
|
||||
],
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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.`
|
||||
},
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -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."
|
||||
}),
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user