# PJ2026-01060703 CI/CD Branch Follower

SPEC: PJ2026-01060703 CI/CD branch follower draft-2026-07-03-p0-branch-follower

## 1. 目标

为 UniDesk 建立一个 YAML-first、Kubernetes 原生的 CI/CD branch follower 组件，自动跟随三个首批运行面的上游 branch，并通过单一 CLI 完成部署、触发和中间状态查询。

首批 follower：

- `hwlab-jd01-v03`: 跟随 `pikasTech/HWLAB@v0.3`，触发 `hwlab-node-runtime` 控制面。
- `agentrun-jd01-v02`: 跟随 `pikasTech/agentrun@v0.2`，触发 JD01 `agentrun-yaml-lane` 控制面。
- `web-probe-sentinel-master`: 跟随 `pikasTech/unidesk@master`，触发 YAML 选中的 web-probe sentinel CI/CD。

## 2. 强约束

- branch observation、source snapshot、build context、publish、closeout 的权威来源只能是 Kubernetes 管理的 git-mirror immutable snapshot 和运行面对象。
- controller pod、Job、Pipeline、publish 流程不得挂载或读取 host source workspace、开发 worktree、`.worktree/*`、local git checkout 或 direct GitHub fallback。
- host worktree 只能作为人工 debug 或 post-deploy 验证入口，不能影响 follower 的 sha 决策、PipelineRun、GitOps 或状态判断。
- 所有可调项进入 YAML；代码只解析 configRef、selector、adapter id、预算和命令，不写隐藏默认。
- registry 不承载运行面/GitOps/Secret 细节；HWLAB、AgentRun、web-probe sentinel 细节仍归属各自 YAML。
- 默认 CLI 输出必须是简洁表格和 drill-down 命令；完整 JSON/YAML 只通过 `--json`、`--raw` 或 `-o json|yaml` 输出。
- 端到端 closeout 预算以 YAML 声明，首批 follower 目标为 120s 内收敛；超预算必须可见，不做无限等待。

## 3. YAML 职责边界

`config/cicd-branch-followers.yaml` 只声明：

- controller 的 namespace、kube route、ServiceAccount、Lease、ConfigMap、镜像和循环预算。
- follower registry：id、enabled、adapter、source ref、target ref、status/trigger/event/log drill-down 命令、closeout check 名称和预算。
- 对拥有配置的引用：`config/hwlab-node-lanes.yaml`、`config/agentrun.yaml`、`config/hwlab-web-probe-sentinel/*.yaml`。

它不声明：

- HWLAB runtime workload、GitOps path、Secret sourceRef、registry image rewrite 细节。
- AgentRun manager/runtime/secret/GitOps 细节。
- Web sentinel scenario/prompt/report/runtime/publicExposure/secret 细节。

## 4. CLI

入口：

```bash
bun scripts/cli.ts cicd branch-follower plan
bun scripts/cli.ts cicd branch-follower apply --confirm --wait
bun scripts/cli.ts cicd branch-follower status
bun scripts/cli.ts cicd branch-follower run-once --all --dry-run
bun scripts/cli.ts cicd branch-follower events --follower hwlab-jd01-v03
bun scripts/cli.ts cicd branch-follower logs --follower hwlab-jd01-v03
```

默认视图显示：

- follower id、adapter、source branch、observed sha、target sha、last triggered sha、last succeeded sha。
- phase：`Observed`、`Noop`、`PendingTrigger`、`Triggering`、`ClosingOut`、`Succeeded`、`Failed`、`Superseded`。
- in-flight job、budget source、controller/state age、next drill-down。

## 5. Controller

`apply` 渲染并下发：

- Namespace。
- ServiceAccount。
- Role/RoleBinding。
- ConfigMap：registry YAML。
- ConfigMap：follower state。
- Lease：leader election anchor。
- Deployment：controller loop。

Deployment 使用 EmptyDir 作为工作目录，只从 Kubernetes git-mirror clone UniDesk controller source，并把 mounted registry 覆盖到 cloned repo 的 `config/cicd-branch-followers.yaml` 后执行：

```bash
bun scripts/cli.ts cicd branch-follower run-once --all --confirm --wait --controller
```

该路径不挂载 host source，不读取 host worktree，不依赖 target dev directory。

## 6. Adapter 合同

每个 adapter 复用既有受控 CLI：

- `hwlab-node-runtime`: `hwlab nodes control-plane status|trigger-current --node JD01 --lane v03`
- `agentrun-yaml-lane`: `agentrun control-plane status|trigger-current --node JD01 --lane jd01-v02`
- `web-probe-sentinel-cicd`: `web-probe sentinel publish-current|control-plane status --node JD01 --lane v03 --sentinel jd01-web-probe-sentinel`

branch follower 不直接操作 Tekton、Argo、kubectl 或 GitHub。它只通过 adapter 命令读取 compact status 或触发已存在的控制面。

## 7. 状态机

```mermaid
stateDiagram-v2
  [*] --> Observed
  Observed --> Noop: observed == target
  Observed --> PendingTrigger: observed != target
  PendingTrigger --> Triggering
  Triggering --> ClosingOut
  ClosingOut --> Succeeded
  ClosingOut --> Failed
  Triggering --> Superseded: branch advanced
  Failed --> PendingTrigger: retryable
  Succeeded --> Observed: next loop
```

## 8. 验收

- `bun scripts/cli.ts cicd branch-follower apply --confirm --wait` 一条 CLI 可完成 controller 更新并等待 K8s 对象 ready。
- `bun scripts/cli.ts cicd branch-follower status` 可查询 controller、state ConfigMap 和三个 follower 的中间状态。
- `bun scripts/cli.ts cicd branch-follower run-once --all --dry-run` 对三个首批 follower 给出 Noop/PendingTrigger/Blocked 决策，不发生写操作。
- 任一 source branch 新 sha 只触发一次；重复 sha 不重复触发；branch advance 时旧 in-flight sha 标记为 Superseded。
- follower 决策和状态不读取 host worktree；故意弄脏/滞后/缺依赖的目标 dev dir 不影响 observed sha、trigger sha 和 closeout 状态。
- Secret/API key 只显示对象名、key 名、presence、fingerprint 或 sourceRef，不打印值。
- 不新增 `full.md` 或超级 Markdown；长期入口在 skill `SKILL.md` 引用拆分后的职责文档。
