# TaskTree 开发与运维参考

## 目录

- [源码与配置](#源码与配置)
- [环境边界](#环境边界)
- [Native-first 开发](#native-first-开发)
- [部署态 CLI 验收](#部署态-cli-验收)
- [自动交付](#自动交付)
- [Web 与运行面验收](#web-与运行面验收)
- [配合技能](#配合技能)

## 源码与配置

- TaskTree 源码位于 HWLAB v0.3：
  - `internal/tasktree/` 保存 contracts、repository、dispatcher、workflow 和 activity；
  - `cmd/hwlab-tasktree-worker/main.ts` 与 `cmd/hwlab-tasktree-api/main.ts` 是独立入口；
  - `tools/src/tasktree-cli.ts` 只选择 transport，不复制业务逻辑；
  - `web/hwlab-cloud-web/src/views/projects/TaskTreeView.vue` 提供甘特图。
- PostgreSQL 唯一真相来自 UniDesk `config/platform-db/postgres-nc01.yaml`。
- TaskTree 运行配置来自 UniDesk `config/hwlab-tasktree.yaml`。
- Temporal 使用共享 `unidesk` logical namespace 和 YAML 声明的 task queue。
- GitHub 灾备配置来自 `config/hwlab-tasktree.yaml#defaults.backup`：
  - PostgreSQL 是在线事务权威；
  - GitHub 是版本化灾备副本；
  - 首版复用 `pikasTech/decision-center-data` 的隔离 `tasktree/<target>` 路径；
  - SSH 身份只引用 `config/deploy-ssh-identities.yaml#github.com`。

## 环境边界

- 日常任务管理从 UniDesk 根目录使用
  `bun scripts/cli.ts tasktree ...`：
  - UniDesk 入口负责解析 owning YAML 和统一 Secret；
  - 本节中的 HWLAB CLI 直调只用于 TaskTree 源码开发和底层诊断。
- 本地 dispatcher 和 native API 需要 `TASKTREE_DATABASE_URL` 或 `DATABASE_URL`。
- worker 额外需要 `TASKTREE_TEMPORAL_ADDRESS`：
  - 地址必须动态解析当前 Temporal Service；
  - 禁止持久化 ClusterIP。
- 可用以下变量覆盖 YAML 对应事实：
  - `TASKTREE_TEMPORAL_NAMESPACE`；
  - `TASKTREE_TEMPORAL_TASK_QUEUE`；
  - `TASKTREE_API_HOST`、`TASKTREE_API_PORT`；
  - `TASKTREE_WORKER_HEALTH_HOST`、`TASKTREE_WORKER_HEALTH_PORT`。
  - `TASKTREE_BACKUP_ENABLED`、`TASKTREE_BACKUP_REPO_SSH_URL`；
  - `TASKTREE_BACKUP_BRANCH`、`TASKTREE_BACKUP_BASE_PATH`；
  - `TASKTREE_BACKUP_WORKTREE`、`TASKTREE_BACKUP_TARGET`；
  - `TASKTREE_BACKUP_INTERVAL_MS`；
  - `TASKTREE_BACKUP_GIT_SSH_COMMAND`；
  - `TASKTREE_BACKUP_GIT_AUTHOR_NAME`、`TASKTREE_BACKUP_GIT_AUTHOR_EMAIL`；
  - `TASKTREE_BACKUP_GIT_COMMIT_PREFIX`。
- 生成的 `DATABASE_URL` 含 `&`：
  - 禁止 `source` 或 `.` 加载生成的 env 文件；
  - 必须通过受控 env parser 读取单个 key；
  - 将结果作为单个环境变量传给进程；
  - 不打印或回显 DSN。

## Native-first 开发

- 开发等级遵循 `$unidesk-devlevel`：
  - 解析器、导入和 dispatcher 领域逻辑使用 L0；
  - HTTP、Temporal worker、PostgreSQL 和 HMR Web 联调使用 L1；
  - L1 收口前不得用 L2/L3 CI/CD 滚动代替本地反馈循环。
- 只在 workflow 测试需要时启动 worker：

```bash
bun run cmd/hwlab-tasktree-worker/main.ts
```

- 使用本地 dispatcher CLI 完成 CRUD、层级、时间节点、报告、timeline 和 workflow：

```bash
bun tools/hwlab-cli/bin/hwlab-cli.ts tasktree health
bun tools/hwlab-cli/bin/hwlab-cli.ts tasktree group list
bun tools/hwlab-cli/bin/hwlab-cli.ts tasktree timeline --group <group-id>
bun tools/hwlab-cli/bin/hwlab-cli.ts tasktree workflow start --task <task-id>
```

- 本地 CLI 默认直接调用 dispatcher，不得要求 API server 存在。
- worker 闭环后再 native 启动 API：

```bash
bun run cmd/hwlab-tasktree-api/main.ts
```

- 用同一命令增加 `--overapi` 验证 HTTP adapter：

```bash
HWLAB_TASKTREE_API_URL=http://127.0.0.1:6673 \
  bun tools/hwlab-cli/bin/hwlab-cli.ts tasktree timeline \
  --group <group-id> --overapi
```

- `--overapi` 只能切换 transport：
  - 命令、参数、DTO、输出 envelope 和错误语义必须保持一致。
- L0 已通过后，L1 API、worker 与 HMR Web 优先使用仓库单一 lifecycle 入口：

```bash
cd web/hwlab-cloud-web
TASKTREE_NATIVE_DATABASE_ENV_FILE=/root/.unidesk/.state/secrets/hwlab/tasktree-nc01-db.env \
TASKTREE_TEMPORAL_ADDRESS="$(trans NC01:k3s kubectl -n temporal get service temporal-frontend \
  -o 'jsonpath={.spec.clusterIP}:{.spec.ports[0].port}')" \
  bun run tasktree:native:start
bun run tasktree:native:status
```

- lifecycle 操作规则：
  - database env 路径必须对应 `config/hwlab-tasktree.yaml` 当前 native target 的
    `database.sourceRef`，不得从运行面反解 DSN；
  - Temporal 地址每次启动时从 Service 动态解析，禁止保存 ClusterIP；
  - `start` 必须在启动前一次性报告缺失输入，并在返回成功前确认 supervisor
    未立即退出；不得让调用方通过 `start → status → logs` 才发现前置条件缺失；
  - `start` 一次拉起三个 TaskTree native 进程；
  - `status` 用一个 JSON 结果判定 supervisor 生命周期；
  - 只有启动或验收失败时才运行 `bun run tasktree:native:logs`；
  - 收口时运行 `bun run tasktree:native:stop`；
  - 不得逐个猜测或清理 PID；
  - lifecycle `status` 不能替代 CLI health、workflow 和浏览器验收。
- API 合同通过后再启动 TaskTree L1 Vite HMR：
  - 复用 Cloud Web 正式 `App.vue`、`AppShell`、顶栏、Router、Pinia 和设计系统；
  - 保留 HWLAB 左侧根导航；
  - 通过 native auth/access profile 只授权 `project.tasktree`；
  - 根导航只能显示 TaskTree 一个页面入口；
  - 只把 `/v1/tasktree` 代理到 native API；
  - 产品壳层不得触发其他 HWLAB 业务请求；
  - 禁止为了总框架启动 Cloud API、Workbench 或其他后端；
  - API 使用 `6673`，worker health 使用 `6674`；
  - Web 默认使用 `4173`；
  - 端口被其他 L1 会话占用时选择独立空闲端口；
  - Web 对外监听时，HMR client 地址由请求来源解析；
  - 禁止把 HMR client 地址写成 `0.0.0.0`；
  - 修改前端时复用现有 HMR 与 API 进程；
  - 不触发镜像构建或 Kubernetes rollout。
- native 进程使用独立 PID、日志和 state 目录：
  - 验收后是否保持运行及任务结束公网 URL 报告统一遵循 `$unidesk-devlevel`；
  - 一次性 disposable smoke 继续按自身隔离合同清理。

## 部署态 CLI 验收

- 线上模式要求 `HWLAB_TASKTREE_API_URL` 或显式 `--api-url`。
- 在原命令末尾增加 `--overapi`，不得维护第二套命令。
- 选定 node 后只读取 target 级入口：
  - 路径为 `config/hwlab-node-lanes.yaml#lanes.<lane>.targets.<node>`；
  - 禁止回退到 lane template 默认 IP 或其他 node URL。
- 公网 Cloud API 需要 HWLAB session 时：
  - 裸 CLI 的未认证响应不能判定 TaskTree API Pod 故障。
- 直连 smoke 在已部署 API Pod 内执行：
  - 使用 Pod 自带的同版本仓库 CLI；
  - `--api-url` 指向 localhost API；
  - repo root、Deployment、container 和 port 从 runtime spec 与 owning YAML 解析；
  - 禁止写死一次性路径。
- 输出只保留：
  - operation；
  - HTTP status；
  - group id；
  - task、subtask、report 和 milestone 计数；
  - 禁止回显报告正文。
- Temporal 部署态 smoke 使用临时 TaskGroup 与 Task：
  - 通过同一 `--overapi` 入口创建；
  - 启动 workflow；
  - 确认 run id、完成状态与 report id；
  - 使用 shell trap 或等价 finally 删除临时 TaskGroup；
  - 禁止改写正式导入组的任务状态或报告计数。

## 自动交付

- native 阶段完成后，才提交 HWLAB source PR。
- HWLAB PR monitor 可能在 PR 创建后自动合并：
  - 创建 PR 本身就是进入 L2 自动交付的授权动作；
  - PR 不是只等待评审的无发布交接；
  - PR 正文中的“不合并”或“不发布”不能阻止自动合并；
  - 任务明确停在 L0/L1 时只提交并推送功能分支；
  - L0/L1-only 禁止创建 PR；
  - 只有已决定进入 L2 时才创建 PR。
- HWLAB v0.3 PR merge 是唯一正式交付触发。
- API 与 worker 保持不同 Deployment、entrypoint、健康检查和 Secret consumption。
- API 与 worker 的环境制品复用规则：
  - 两者属于 `gitops/reuse.ymal#spec.envArtifactGroups.hwlab-ts-runtime-env`；
  - 两者共享依赖 identity 和环境镜像；
  - 两者保留各自代码 identity；
  - 环境必须重建时最多只构建一个 TaskTree 环境；
  - code-only 变更应保持零环境构建；
  - 只滚动受影响的独立 workload。
- TaskTree CI 性能检查使用仓库只读 planner：

```bash
node scripts/ci-plan.mjs \
  --lane v03 \
  --base-ref <base-ref> \
  --target-ref <target-ref> \
  --services hwlab-tasktree-api,hwlab-tasktree-worker
```

- planner 判定：
  - 两个服务的 `environmentInputHash` 和 `environmentImage` 必须相同；
  - TaskTree 共享代码变更时，两者同时进入 `affectedServices`；
  - 环境必须重建时，`buildServices` 只包含一个 TaskTree 服务。
- 禁止人工 mirror sync、PipelineRun、Argo sync 或直接修改 Kubernetes workload。
- 只通过 `$unidesk-cicd` 观察自动交付收敛。
- 上线后保留 native worker 与本地 dispatcher CLI。

## Web 与运行面验收

- 默认 CLI 在只启动 native worker 时完成全能力 smoke。
- GitHub 灾备 native 验收：
  - 先运行 `backup create --dry-run` 检查实体计数；
  - worker 启动后等待自动快照；
  - 使用 `backup status` 检查成功时间、内容 SHA 和 Git commit；
  - 使用 `backup verify` 确认数据库与 GitHub 内容 SHA 一致；
  - 使用 `backup restore` 只做共享数据库恢复规划；
  - 真实恢复只允许在 disposable 数据库或隔离 schema 验证；
  - 禁止使用共享开发或生产数据库验证破坏性恢复。
- native API 与 `--overapi` 返回同合同结果。
- 自动交付后 API 和 worker 独立 ready。
- 线上 workflow 必须被部署 worker 消费。
- 使用 repo-owned typed 浏览器入口：

```bash
bun scripts/cli.ts web-probe console-verify \
  --node NC01 \
  --lane v03 \
  --origin internal \
  --profile tasktree
```

- 浏览器验收必须覆盖：
  - `1920x1080`、`960x600`、`390x844`；
  - task/subtask 标签与甘特条、milestone；
  - group 深链刷新恢复；
  - 详情弹框边界；
  - ExecutionReport 的安全 Markdown Viewer 和长报告内部滚动；
  - 大型历史任务导入后的长标题、深层压平、折叠和纵向滚动；
  - `/projects/tasktree` 默认显示全局 TaskGroup 甘特视图；
  - 全局概览使用 PostgreSQL 单次聚合 API；
  - 禁止前端逐组请求 timeline；
  - 详情页支持三级缩进和逐级折叠；
  - 大纲编号、层级控件和 Markdown 标题遵循
    `$unidesk-webdev` 的结构化树设计规则；
  - 左侧标题与右侧时间条的组内滚动同步；
  - 标题占满可用单行宽度后才使用省略号；
  - Markdown 链接渲染为链接；
  - 时间刻度和画布填满右侧可用区域；
  - 放大后才出现横向滚动；
  - 任务说明和执行报告共用 Markdown 阅读面板；
  - 弹窗与右侧吸附两种详情模式；
  - `task=<task-id>` 和 `detail=docked` 深链恢复；
  - 三栏模式等高并各自内部滚动；
  - document 无横向或纵向溢出；
  - console、`pageerror`、失败请求和失败响应均为零。
- 截图必须等待 `.platform-shell` 或 TaskTree ready selector。
- 禁止把入口脚本尚未挂载时的空白首帧当成白屏。
- 临时 ID 只作为 smoke 证据：
  - 禁止写入 owning YAML 或长期 skill。

## 配合技能

- Temporal 基础设施与通用敏捷闭环使用 `$unidesk-temporal`。
- 开发等级使用 `$unidesk-devlevel`。
- CI/CD 观察使用 `$unidesk-cicd`。
- Web 验收使用 `$unidesk-webdev`。
- YAML 配置使用 `$unidesk-ymalops`。
- GitHub issue/PR 使用 `$unidesk-gh`。
