Compare commits
6
Commits
v0.1.0
..
c53bde4cf3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c53bde4cf3 | ||
|
|
88204a90c8 | ||
|
|
d6567b1842 | ||
|
|
4518f41fd4 | ||
|
|
445940ea63 | ||
|
|
18ffce5d29 |
@@ -8,7 +8,7 @@ the corpus internally consistent and publish-ready.
|
||||
The corpus does not assume any specific forge (GitHub / Gitea / GitLab),
|
||||
ticketing, or CI system. System-specific behavior lives behind an explicit
|
||||
adapter contract (`core/adapters/`), so the same core can be adopted by any
|
||||
octopus instance — or any other agent platform — with its own adapters.
|
||||
octopus instance 鈥?or any other agent platform 鈥?with its own adapters.
|
||||
|
||||
## Layout
|
||||
|
||||
@@ -20,7 +20,7 @@ octopus instance — or any other agent platform — with its own adapters.
|
||||
| `core/templates/` | Artifact templates (DAG, iteration docs) |
|
||||
| `core/schemas/` | JSON schemas under the public namespace `https://eightarms.net/octopus-workflow/schemas/` |
|
||||
| `core/adapters/` | Adapter contract: terminology SSOT + Gitea reference implementation |
|
||||
| `core/CORE-MANIFEST.json` | Registry of core↔instance mappings and sync semantics (verbatim / verbatimDir / rewritten / split / core-only) |
|
||||
| `core/CORE-MANIFEST.json` | Registry of core鈫攊nstance mappings and sync semantics (verbatim / verbatimDir / rewritten / split / core-only) |
|
||||
| `examples/` | Organization-agnostic narrative essays referencing the core |
|
||||
| `guards/` | Standalone drift guards (bun + node stdlib only) |
|
||||
|
||||
@@ -32,6 +32,7 @@ Runnable inside this repo with [bun](https://bun.sh), no install step needed:
|
||||
bun run check:core-cohesion # corpus structural invariants
|
||||
bun run check:core-p1 # publish-readiness neutrality (no org-internal links)
|
||||
bun run delink:core -- --check # no replaceable org-internal refs remain
|
||||
bun run check:encoding-health # core/ text is clean UTF-8 (no GBK mojibake)
|
||||
```
|
||||
|
||||
The instance-side guards (`check-core-parity`, `check-schema-ids`,
|
||||
|
||||
@@ -9,8 +9,8 @@ Core 与 octopus 实例(dogfood)之间的兼容性契约。随各 Increment
|
||||
| core 版本 | 对应 octopus 侧状态 | 兼容说明 |
|
||||
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 0.x(Increment 1–4:骨架 + G0–G4 全量迁移) | octopus 实例 `.octopus/` 为消费镜像;core 与 dogfood 内容逐字/改写对齐 | core 是 SSOT 权威副本;dogfood 经 `script/core-sync.sh` 单向同步。schema 尚未迁入 core。 |
|
||||
| 0.x(Increment 5:schema $id 迁移四件套) | dogfood `.octopus/schemas/*.json` 的 `$id` **保持旧命名空间不动**(活系统仍引用);core 侧 `$id` 已迁至 `https://eightarms.net/octopus-workflow/schemas/` | 双轨期:core schema 与 dogfood schema 是**不同 $id 的两份文件**(manifest 登记为 `rewritten`,不逐字同步)。活归档 run 的 index.json 携带旧 $id,读取侧经别名表解析。 |
|
||||
| 1.0.0(首个 semver 发布,规划中) | 发布仓创建;live 迁移(dogfood 侧切新命名空间)完成 | `id-aliases.json` 置 `frozen: true`——$id 一经发布不可变(v3 §G)。别名保留 ≥2 个 major 版本。 |
|
||||
| 0.x(Increment 5:schema $id 迁移四件套) | dogfood `.octopus/schemas/*.json` 的 `$id` 曾**保持旧命名空间不动**(活系统仍引用);core 侧 `$id` 已迁至 `https://eightarms.net/octopus-workflow/schemas/` | 双轨期:core schema 与 dogfood schema 是**不同 $id 的两份文件**(manifest 登记为 `rewritten`,不逐字同步)。活归档 run 的 index.json 携带旧 $id,读取侧经别名表解析。**注记(2026-09):live 迁移已完成——dogfood 侧已切新命名空间,双轨结束**。 |
|
||||
| 1.0.0(首个 semver 发布) | 发布仓创建;live 迁移(dogfood 侧切新命名空间)已完成(2026-09) | `id-aliases.json` 已置 `frozen: true`(2026-09)——$id 一经发布不可变(v3 §G)。别名保留 ≥2 个 major 版本。 |
|
||||
|
||||
## builtin overlay 语料兼容
|
||||
|
||||
|
||||
+2
-2
@@ -44,7 +44,7 @@
|
||||
- `script/check-scaffold-parity.ts` — scaffold-template twin 逐字节
|
||||
校验(schema $id owner token 归一化比较);
|
||||
- `script/delink-core.ts` — 去链接化契约执行(#NNNN 活引用 → [org-internal #NNNN]
|
||||
注记;幂等;--check 零剩余才过;Inc 6b 字节锁镜像翻转 rewritten 后无递延);
|
||||
注记,`--strip` 进一步收敛为溯源短注 [TT-NNNN];幂等;--check 零剩余才过;Inc 6b 字节锁镜像翻转 rewritten 后无递延);
|
||||
- `script/check-core-p1.ts` — P1 零残留终验(私网 IP / 实例主机名 / 个人
|
||||
身份 / 旧 owner token 全树 grep;豁免 id-aliases.json 与历史命名空间
|
||||
URL 声明;Inc 6b 起无字节锁递延);
|
||||
@@ -90,7 +90,7 @@ G0–G4 批次已完成全量迁移(14 规则、17 技能整目录、\_shared
|
||||
- **HARD**(全 core 生效,含 adapters):实例主机名、内网 IP 段、实例
|
||||
配置路径——实例机密与实例专有地址任何 core 文件不得出现。
|
||||
- **SOFT**(`core/adapters/**` 豁免):`.octopus/`、`packages/octopus`、
|
||||
MCP 工具名、工作树路径等实例绑定内容——adapter 目录是 Gitea 参考
|
||||
后端绑定内容(REST 端点、工作树路径等)——adapter 目录是 Gitea 参考
|
||||
实现,允许承载;其余 core 文件不得出现。
|
||||
|
||||
G0 三份规则是从实例规则**逐字复制**的,规则正文里出现实例路径字样属
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
| --- | --- |
|
||||
| 工单后端(ticket backend) | Gitea |
|
||||
| Tier-2 工件库 | Gitea wiki |
|
||||
| 工单评论 API(ticket backend 评论接口) | `gitea_issue_comment__*` |
|
||||
| wiki 读写 API(Tier-2 工件库读写接口) | `gitea_wiki__*` |
|
||||
| 看板移动 API(工单看板列迁移接口) | `gitea_column__move_issue` |
|
||||
| 项目看板 API(工单面板管理接口) | `gitea_project__*` |
|
||||
| 工单评论 API(ticket backend 评论接口) | Gitea REST 评论端点族:`GET/POST /repos/{owner}/{repo}/issues/{index}/comments`、`PATCH /repos/{owner}/{repo}/issues/comments/{id}` |
|
||||
| wiki 读写 API(Tier-2 工件库读写接口) | Gitea REST wiki 端点族:`wiki/pages` GET、`wiki/page/{pageName}` GET/PATCH、`wiki/new` POST(路径前缀 `/api/v1/repos/{owner}/{repo}/`) |
|
||||
| 看板移动 API(工单看板列迁移接口) | Gitea REST projects 相关端点(经 `swagger.v1.json` 查询后调用,勿臆造路径) |
|
||||
| 项目看板 API(工单面板管理接口) | Gitea REST projects/columns 端点族:`GET /repos/{owner}/{repo}/projects`、`GET /repos/{owner}/{repo}/projects/{project_id}/columns` |
|
||||
| 路由解析工具(Step 0 路由门依赖) | `route_resolver` |
|
||||
| 会话工作树路径(并发分支工作区根) | `<worktrees-root>` |
|
||||
| 测试命令·变更集(本地前置检查) | `bun run test:changed` |
|
||||
|
||||
+101
-65
@@ -2,34 +2,37 @@
|
||||
|
||||
> Gitea adapter 参考实现(Increment 3,自 dogfood 源
|
||||
> `_shared/gitea-write-patterns.md` 拆分上提)。本目录承载后端绑定的
|
||||
> API 形态(MCP 工具名、REST 端点、curl 形态);页名规范与寻址语义
|
||||
> API 形态(REST 端点 + swagger 契约,curl 形态);页名规范与寻址语义
|
||||
> 是后端中立契约,见 `core/rules/artifact-addressing.md`(本文不重复)。
|
||||
> 实例基址由实例配置提供(下文 `<gitea-base-url>`),见
|
||||
> `core/adapters/TERMINOLOGY.md`。
|
||||
> `core/adapters/TERMINOLOGY.md`。认证一律 `-H "Authorization: token <token>"`;
|
||||
> 端点契约以 `<gitea-base-url>/swagger.v1.json` 为唯一正典(按需 jq 提取,
|
||||
> 见 `core/skills/gitea-rest/`)。
|
||||
|
||||
Owner/repo 固定为 `Octopus/octopus`。所有 wiki 页名遵循 Core 契约
|
||||
`{slug}/{type}-{seq:02d}-{title}`(例外页全枚举见 artifact-addressing.md)。
|
||||
|
||||
## Wiki URL 构造 — html_url 规则
|
||||
|
||||
**黄金规则:绝不手工拼接 wiki URL。** `gitea_wiki__create_page` /
|
||||
`gitea_wiki__get_page` / `gitea_wiki__list_pages` 响应中的 `html_url`
|
||||
字段是唯一权威链接,发布时捕获并原样复用。`page_name` → `html_url`
|
||||
的变换不可推导(`/`→`%2F`、含斜杠页名带 `.-` 尾缀、CJK 百分号编码),
|
||||
必须读 API。
|
||||
**黄金规则:绝不手工拼接 wiki URL。** `POST .../wiki/new`、
|
||||
`GET .../wiki/page/{mangled-name}`、`GET .../wiki/pages` 响应中的
|
||||
`html_url` 字段是唯一权威链接,发布时捕获并原样复用。页名 →
|
||||
`html_url` 的变换不可推导(`/`→`%2F`、含斜杠页名带 `.-` 尾缀、CJK
|
||||
百分号编码),必须读 API。
|
||||
|
||||
**两种标识符勿混淆**:
|
||||
|
||||
| 标识符 | 是什么 | 用途 |
|
||||
| ----------- | ------------------------------------ | ---------------------------------------- |
|
||||
| `page_name` | 原始页标识;字面 `/`、无主机、无编码 | wiki MCP 工具的 `page_name`/`title` 参数 |
|
||||
| `html_url` | 后端生成的完整可点击 URL | markdown 链接、`target_url`、PR 正文 |
|
||||
| 标识符 | 是什么 | 用途 |
|
||||
| ------ | ------ | ---- |
|
||||
| 逻辑页名(`title`) | 原始页标识;字面 `/`、无主机、无编码 | 写侧:`POST .../wiki/new` 的 `title`;`PATCH` 省略 `title` 保名 |
|
||||
| mangled `pageName`(`sub_url`) | 后端改写的存储名(含 `%2F` 编码与 `.-` 尾缀) | 读侧/改侧路径参数:先 `GET .../wiki/pages` 拿 `sub_url`,**原样**用于 `wiki/page/{pageName}`,绝不手工拼 |
|
||||
| `html_url` | 后端生成的完整可点击 URL | markdown 链接、`target_url`、PR 正文 |
|
||||
|
||||
**去向**:
|
||||
|
||||
- **工件索引位置列** — 一个单元格同时存两者:
|
||||
``[`{page_name}`]({html_url})``。链接文本供读侧调
|
||||
`gitea_wiki__get_page`,href 供人点击(见 Pattern 10)。
|
||||
``[`{page_name}`]({html_url})``。链接文本供读侧回读该页,href 供人
|
||||
点击(见 Pattern 10)。
|
||||
- **commit-status `target_url`** — 终报页的 `html_url`(见 Pattern 8)。
|
||||
- **页内交叉链接** — 用 `html_url`。
|
||||
|
||||
@@ -37,38 +40,56 @@ Owner/repo 固定为 `Octopus/octopus`。所有 wiki 页名遵循 Core 契约
|
||||
|
||||
## Pattern 1: create-wiki-page
|
||||
|
||||
```bash
|
||||
curl -fsS -X POST "<gitea-base-url>/api/v1/repos/Octopus/octopus/wiki/new" \
|
||||
-H "Authorization: token <token>" -H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"title": "{slug}/{type}-{seq:02d}-{title}",
|
||||
"content_base64": "<base64(内容)>",
|
||||
"message": "{可选 commit message}"
|
||||
}'
|
||||
```
|
||||
gitea_wiki__create_page(owner="Octopus", repo="octopus",
|
||||
title="{slug}/{type}-{seq:02d}-{title}",
|
||||
content="{内容}",
|
||||
message="{可选 commit message}")
|
||||
```
|
||||
|
||||
**base64 陷阱(强制注明)**:wiki 写接口只认 `content_base64`;传
|
||||
`content` 会被静默忽略(无报错、返回 2xx,页面存成 0 字节)。正文必须
|
||||
先 base64 编码,且发布后回读确认非空。
|
||||
|
||||
**发布→验证(强制)**:发布后立刻回读确认存在且内容一致:
|
||||
|
||||
```
|
||||
gitea_wiki__get_page(owner="Octopus", repo="octopus", page_name="{同 title}")
|
||||
```bash
|
||||
# 1. 列页拿 mangled sub_url(绝不手工拼 mangled name)
|
||||
curl -fsS -H "Authorization: token <token>" \
|
||||
"<gitea-base-url>/api/v1/repos/Octopus/octopus/wiki/pages"
|
||||
# 2. 用返回的 sub_url 原样读页
|
||||
curl -fsS -H "Authorization: token <token>" \
|
||||
"<gitea-base-url>/api/v1/repos/Octopus/octopus/wiki/page/{sub_url}"
|
||||
```
|
||||
|
||||
404 / 内容不一致 → 修复后重发。页名冲突(409)→ 该页已存在,改用
|
||||
Pattern 2 update,绝不另发新页。响应的 `html_url` 立即捕获复用。
|
||||
404 / 内容为空或不一致 → 修复后重发。页名冲突(409)→ 该页已存在,
|
||||
改用 Pattern 2 update,绝不另发新页。响应的 `html_url` 立即捕获复用。
|
||||
|
||||
## Pattern 2: update-wiki-page
|
||||
|
||||
```
|
||||
gitea_wiki__update_page(owner="Octopus", repo="octopus",
|
||||
page_name="{页名}",
|
||||
content="{新内容}",
|
||||
message="{commit message}")
|
||||
```bash
|
||||
curl -fsS -X PATCH "<gitea-base-url>/api/v1/repos/Octopus/octopus/wiki/page/{sub_url}" \
|
||||
-H "Authorization: token <token>" -H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"content_base64": "<base64(新内容)>",
|
||||
"message": "{commit message}"
|
||||
}'
|
||||
```
|
||||
|
||||
更新后再回读验证;409 冲突 → 拉最新内容手工合并后重试。
|
||||
路径参数用 mangled `sub_url`(先 `GET .../wiki/pages` 获取,原样使用)。
|
||||
**省略 `title` 保持页名不变**——只发 `content_base64`+`message`。
|
||||
同样只认 `content_base64`(`content` 会静默存 0 字节页)。更新后再回读
|
||||
验证;409 冲突 → 拉最新内容手工合并后重试。
|
||||
|
||||
## Pattern 3: create-issue
|
||||
|
||||
```
|
||||
gitea_issue__create(owner="Octopus", repo="octopus",
|
||||
title="{标题}", body="{正文}", labels=["{label}"])
|
||||
```bash
|
||||
curl -fsS -X POST "<gitea-base-url>/api/v1/repos/Octopus/octopus/issues" \
|
||||
-H "Authorization: token <token>" -H "Content-Type: application/json" \
|
||||
-d '{"title":"{标题}","body":"{正文}","labels":[{label_id}]}'
|
||||
```
|
||||
|
||||
### 工单交叉链接(强制)
|
||||
@@ -86,9 +107,10 @@ gitea_issue__create(owner="Octopus", repo="octopus",
|
||||
|
||||
## Pattern 4: update-issue
|
||||
|
||||
```
|
||||
gitea_issue__update(owner="Octopus", repo="octopus",
|
||||
index={issue_number}, body="{正文}", state="{open|closed}", ...)
|
||||
```bash
|
||||
curl -fsS -X PATCH "<gitea-base-url>/api/v1/repos/Octopus/octopus/issues/{index}" \
|
||||
-H "Authorization: token <token>" -H "Content-Type: application/json" \
|
||||
-d '{"body":"{正文}","state":"{open|closed}"}'
|
||||
```
|
||||
|
||||
原位更新正文(checklist 勾选、live 状态表维护);关闭工单即触发
|
||||
@@ -96,9 +118,10 @@ gitea_issue__update(owner="Octopus", repo="octopus",
|
||||
|
||||
## Pattern 5: add-issue-comment
|
||||
|
||||
```
|
||||
gitea_issue_comment__create(owner="Octopus", repo="octopus",
|
||||
index={issue_number}, body="{评论正文}")
|
||||
```bash
|
||||
curl -fsS -X POST "<gitea-base-url>/api/v1/repos/Octopus/octopus/issues/{index}/comments" \
|
||||
-H "Authorization: token <token>" -H "Content-Type: application/json" \
|
||||
-d '{"body":"{评论正文}"}'
|
||||
```
|
||||
|
||||
首次评论后捕获返回的 `comment_id`——后续对同一逻辑评论的更新必须走
|
||||
@@ -107,33 +130,42 @@ Pattern 6 原位 edit,绝不再 create。用于:评审综合(Synthesis)
|
||||
|
||||
## Pattern 6: edit-issue-comment
|
||||
|
||||
```
|
||||
gitea_issue_comment__edit(owner="Octopus", repo="octopus",
|
||||
comment_id={comment_id}, body="{新正文}")
|
||||
```bash
|
||||
curl -fsS -X PATCH "<gitea-base-url>/api/v1/repos/Octopus/octopus/issues/comments/{comment_id}" \
|
||||
-H "Authorization: token <token>" -H "Content-Type: application/json" \
|
||||
-d '{"body":"{新正文}"}'
|
||||
```
|
||||
|
||||
单评论聚合不变量(工件索引、当前状态表等)的执行手段。
|
||||
|
||||
## Pattern 7: move-issue-to-column
|
||||
|
||||
```
|
||||
gitea_column__move_issue(owner="Octopus", repo="octopus",
|
||||
project_id={project_id}, column_id={column_id}, index={issue_number})
|
||||
```
|
||||
看板列迁移(Todo → In Progress → Review → Done)。projects/columns
|
||||
发现用 REST;「把工单移到列」的操作端点语义复杂,经 swagger 查询后
|
||||
调用,不臆造路径:
|
||||
|
||||
看板列迁移(Todo → In Progress → Review → Done)。
|
||||
```bash
|
||||
# 列出 repo 级 projects(projects 仅 repo 级,无 org/user 级端点)
|
||||
curl -fsS -H "Authorization: token <token>" \
|
||||
"<gitea-base-url>/api/v1/repos/Octopus/octopus/projects"
|
||||
# 列某 project 的 columns
|
||||
curl -fsS -H "Authorization: token <token>" \
|
||||
"<gitea-base-url>/api/v1/repos/Octopus/octopus/projects/{project_id}/columns"
|
||||
# 移动工单到列:先经 swagger.v1.json 查询 projects 相关端点后调用
|
||||
curl -s <gitea-base-url>/swagger.v1.json -o /tmp/gitea-sw.json
|
||||
jq -r '.paths | keys[]' /tmp/gitea-sw.json | grep projects
|
||||
```
|
||||
|
||||
## Pattern 7.5: move-issue-to-pipeline-stage
|
||||
|
||||
管线阶段板列(Pipeline Stages board column)承载阶段迁移——阶段转移
|
||||
落到板列,**不落** `## 当前状态` 行(该表只承载 PR / 评审 / CI 行与
|
||||
非阶段阻塞项)。列序列按管线阶段定义;移动用 Pattern 7 同款
|
||||
`gitea_column__move_issue`,column 由 `gitea_project__list` /
|
||||
`gitea_column__list` 发现。
|
||||
非阶段阻塞项)。列序列按管线阶段定义;移动与 Pattern 7 同款
|
||||
(projects/columns 经 REST + swagger 发现,同上)。
|
||||
|
||||
## Pattern 8: post-commit-status(REST 回退)
|
||||
## Pattern 8: post-commit-status
|
||||
|
||||
MCP 工具缺席时用 REST 直发 commit status(评审综合的 Tier-2 落点):
|
||||
commit status 直发 REST(评审综合的 Tier-2 落点):
|
||||
|
||||
```bash
|
||||
curl -X POST "<gitea-base-url>/api/v1/repos/Octopus/octopus/statuses/{sha}" \
|
||||
@@ -153,16 +185,19 @@ merge 前读回验证:`GET /commits/{PR_SHA}/status`。
|
||||
|
||||
## Pattern 9: create-iteration-board
|
||||
|
||||
```
|
||||
gitea_project__create(owner="Octopus", repo="octopus",
|
||||
title="{slug} — Iteration {N}", description="…")
|
||||
gitea_column__create(owner="Octopus", repo="octopus",
|
||||
project_id={project_id}, title="Todo")
|
||||
# … In Progress / Review / Done 同款
|
||||
```bash
|
||||
# 建 project(board):先经 swagger 查询 create 端点契约
|
||||
curl -s <gitea-base-url>/swagger.v1.json -o /tmp/gitea-sw.json
|
||||
jq '.paths["/repos/{owner}/{repo}/projects"].post' /tmp/gitea-sw.json
|
||||
# 随后 POST 建板(title="{slug} — Iteration {N}", description="…")
|
||||
# 再对每列(Todo / In Progress / Review / Done):
|
||||
jq '.paths["/repos/{owner}/{repo}/projects/{project_id}/columns"].post' /tmp/gitea-sw.json
|
||||
# 随后 POST 建列
|
||||
```
|
||||
|
||||
DAG 聚合 agent 在单门 PASS 后建板;工单正文模板带 `## Node Reference`
|
||||
(指向 `{epic-slug}/dag`)、`## Acceptance Criteria`、`## Parent`。
|
||||
projects 仅 repo 级。DAG 聚合 agent 在单门 PASS 后建板;工单正文模板带
|
||||
`## Node Reference`(指向 `{epic-slug}/dag`)、`## Acceptance Criteria`、
|
||||
`## Parent`。
|
||||
|
||||
## Pattern 10: artifact-index(工单 ↔ 工件索引)
|
||||
|
||||
@@ -170,14 +205,15 @@ DAG 聚合 agent 在单门 PASS 后建板;工单正文模板带 `## Node Refer
|
||||
索引(反向链接 + compaction 恢复主路径;语义不变量见
|
||||
`core/rules/artifact-addressing.md` §4):
|
||||
|
||||
```
|
||||
```bash
|
||||
# 1. 找源工单(PR body / commit 的 Closes #N,或 DAG 父映射);无则跳过
|
||||
# 2. 评论已存在?
|
||||
gitea_issue_comment__list(owner="Octopus", repo="octopus", index={issue_number})
|
||||
curl -fsS -H "Authorization: token <token>" \
|
||||
"<gitea-base-url>/api/v1/repos/Octopus/octopus/issues/{index}/comments"
|
||||
# → 扫 body 以 "## 工件索引" 开头的评论(遗留前缀 "## Pipeline 工件追踪表"
|
||||
# 原位升级,不重复发)
|
||||
# 3a. 不存在 → gitea_issue_comment__create 初始化
|
||||
# 3b. 存在 → gitea_issue_comment__edit 原位编辑(复用 comment_id)
|
||||
# 3a. 不存在 → POST .../issues/{index}/comments 初始化
|
||||
# 3b. 存在 → PATCH .../issues/comments/{comment_id} 原位编辑(复用 comment_id)
|
||||
```
|
||||
|
||||
**索引表模板**(每工件一行;技能只增改自己的行,绝不删他技的行):
|
||||
@@ -191,11 +227,11 @@ gitea_issue_comment__list(owner="Octopus", repo="octopus", index={issue_number})
|
||||
| DAG | 任务图 | v1 (frozen) | [`{epic-slug}/dag`]({html_url}) | CORE |
|
||||
|
||||
**位置列填充规则**:单元格 = markdown 链接 ``[`{page_name}`]({html_url})``;
|
||||
链接文本(page_name,字面 `/`)供读侧 `gitea_wiki__get_page`;href
|
||||
(html_url)供人点击,必须取自 API 响应,严禁拼接。
|
||||
链接文本(逻辑页名,字面 `/`)供读侧先 `GET .../wiki/pages` 拿 `sub_url`
|
||||
后回读该页;href(html_url)供人点击,必须取自 API 响应,严禁拼接。
|
||||
|
||||
**重读优先级**:`CORE` = compaction 后必读(重读集 = 全部 CORE 行);
|
||||
`ON-Demand` → `ON-DEMAND` = 按需;`ARCHIVE` = 已归档不读。
|
||||
`ON-DEMAND` = 按需;`ARCHIVE` = 已归档不读。
|
||||
|
||||
**归档动作(archive-at-close)**:工单关闭时由关闭方 agent 原位 edit
|
||||
本评论——表格上方加归档横幅(`> **状态**: ✅ 已归档 — issue #{N} 关闭于
|
||||
|
||||
@@ -12,7 +12,12 @@ Owner/repo 固定 `Octopus/octopus`。compaction 恢复从 Pattern 6
|
||||
## Pattern 1: read-wiki-page
|
||||
|
||||
```
|
||||
gitea_wiki__get_page(owner="Octopus", repo="octopus", page_name="{slug}/{page_title}")
|
||||
# 1. 列 wiki 页拿 mangled sub_url(绝不手工拼 mangled name)
|
||||
curl -fsS -H "Authorization: token <token>" \
|
||||
"<gitea-base-url>/api/v1/repos/Octopus/octopus/wiki/pages"
|
||||
# 2. 用返回的 sub_url 原样读页(含 %2F 编码与 .- 尾缀)
|
||||
curl -fsS -H "Authorization: token <token>" \
|
||||
"<gitea-base-url>/api/v1/repos/Octopus/octopus/wiki/page/{mangled-name}"
|
||||
```
|
||||
|
||||
常用页名(全量文法 + 例外枚举见 `core/rules/artifact-addressing.md` §2):
|
||||
@@ -45,7 +50,7 @@ gitea_wiki__get_page(owner="Octopus", repo="octopus", page_name="{slug}/{page_ti
|
||||
`{slug}/roadmap/{page}`、`{slug}/shared/{file}`、
|
||||
`{slug}/reviews/{roadmap|design-space|plan}/final/report`。
|
||||
|
||||
**本地回退(wiki MCP 工具不可用)**:读本地 wiki 克隆(实例路径见
|
||||
**本地回退(REST 不可达时)**:读本地 wiki 克隆(实例路径见
|
||||
TERMINOLOGY.md)。wiki 文件名 URL 编码(`/`→`%2F`,`.md` 前可能带
|
||||
`.-`),用 glob 而非固定路径解析:
|
||||
|
||||
@@ -56,7 +61,8 @@ glob(pattern="*{slug}*{page-title}*.md", path="<local-wiki-clone>/{repo}-wiki/")
|
||||
## Pattern 2: read-issue
|
||||
|
||||
```
|
||||
gitea_issue__get(owner="Octopus", repo="octopus", index={issue_number})
|
||||
curl -fsS -H "Authorization: token <token>" \
|
||||
"<gitea-base-url>/api/v1/repos/Octopus/octopus/issues/{issue_number}"
|
||||
```
|
||||
|
||||
读工单详情、正文、元数据(label、assignee、milestone、state)。
|
||||
@@ -64,20 +70,28 @@ gitea_issue__get(owner="Octopus", repo="octopus", index={issue_number})
|
||||
## Pattern 3: read-issue-comments
|
||||
|
||||
```
|
||||
gitea_issue_comment__list(owner="Octopus", repo="octopus", index={issue_number})
|
||||
curl -fsS -H "Authorization: token <token>" \
|
||||
"<gitea-base-url>/api/v1/repos/Octopus/octopus/issues/{issue_number}/comments?page=N&limit=50"
|
||||
```
|
||||
|
||||
分页用 `page`/`limit`(上限 50),响应头 `x-total-count` 给总数。
|
||||
|
||||
读工单全部评论(评审结果、状态备注、讨论线程)。
|
||||
|
||||
## Pattern 4: read-project-column-issues
|
||||
|
||||
看板列工单队列。project/column 发现:
|
||||
|
||||
```
|
||||
gitea_column__list_issues(owner="Octopus", repo="octopus",
|
||||
project_id={project_id}, column_id={column_id})
|
||||
curl -fsS -H "Authorization: token <token>" \
|
||||
"<gitea-base-url>/api/v1/repos/Octopus/octopus/projects"
|
||||
curl -fsS -H "Authorization: token <token>" \
|
||||
"<gitea-base-url>/api/v1/repos/Octopus/octopus/projects/{project_id}/columns"
|
||||
```
|
||||
|
||||
看板列工单队列。project/column 发现:`gitea_project__list` +
|
||||
`gitea_column__list`。
|
||||
「把工单移到列」等复杂操作:经 `swagger.v1.json`
|
||||
(`jq '.paths | keys[]' | grep projects`)查询 projects 相关端点后调用,
|
||||
不要臆造具体端点路径。projects 仅 repo 级(无 org/user 级端点)。
|
||||
|
||||
## Pattern 5: read-review-status(CLI)
|
||||
|
||||
@@ -103,17 +117,24 @@ success,1 = 有 failure/error。
|
||||
而非猜测页名路径:
|
||||
|
||||
```
|
||||
gitea_issue__get(owner="Octopus", repo="octopus", index={issue_number})
|
||||
gitea_issue_comment__list(owner="Octopus", repo="octopus", index={issue_number})
|
||||
# 找 body 以 "## 工件索引"(遗留 "## Pipeline 工件追踪表")开头的评论
|
||||
gitea_wiki__get_page(owner="Octopus", repo="octopus", page_name=page_name)
|
||||
# 1. 读源工单
|
||||
curl -fsS -H "Authorization: token <token>" \
|
||||
"<gitea-base-url>/api/v1/repos/Octopus/octopus/issues/{issue_number}"
|
||||
# 2. 拉评论列表,找 body 以 "## 工件索引"(遗留 "## Pipeline 工件追踪表")开头的评论
|
||||
curl -fsS -H "Authorization: token <token>" \
|
||||
"<gitea-base-url>/api/v1/repos/Octopus/octopus/issues/{issue_number}/comments?page=N&limit=50"
|
||||
# 3. 按 CORE 行位置列逐个读工件页:先 GET .../wiki/pages 拿 sub_url(mangled
|
||||
# name),再原样请求
|
||||
curl -fsS -H "Authorization: token <token>" \
|
||||
"<gitea-base-url>/api/v1/repos/Octopus/octopus/wiki/page/{mangled-name}"
|
||||
```
|
||||
|
||||
**位置列提取规则**:单元格形如 ``[`{page_name}`]({html_url})`` ——
|
||||
取**链接文本**(首个 `[` 与 `]` 之间、剥反引号)作为 page_name,不是
|
||||
href(含 `%2F`/`.-`,API 不认)。裸 page_name 单元格(无链接包裹)也
|
||||
接受:整格即 page_name。形如 `#comment-{id}` 的值改用
|
||||
`gitea_issue_comment__list` 读,不得喂给 `gitea_wiki__get_page`。
|
||||
`GET .../issues/{index}/comments` 拉工单评论列表后按 id 取,不得当作
|
||||
wiki 页名去读 wiki 端点。
|
||||
|
||||
**重读规则**:重读集 = 全部 `CORE` 行;`ON-DEMAND` 行仅当前任务需要
|
||||
时读;绝不读 `ARCHIVE` 行。索引缺失(历史工单)→ 回退 issue body +
|
||||
|
||||
@@ -67,7 +67,7 @@ creating thin wrapper checklist files would add no value.
|
||||
|
||||
| # | 检查项 | 通过 | 不通过 | 备注 |
|
||||
| --- | --------------------------------------------------------------------- | ---- | ------ | ---- |
|
||||
| 1.1 | SDLC 流水线各阶段均有对应 skill(analyze-dag→review-dag 单门→implement→review-code→verify→release→retrospective;legacy roadmap/requirements/design/plan 已归档 [org-internal #3072] phase 3,见 `<instance-root>/archive/`) | ☐ | ☐ | |
|
||||
| 1.1 | SDLC 流水线各阶段均有对应 skill(analyze-dag→review-dag 单门→implement→review-code→verify→release→retrospective;legacy roadmap/requirements/design/plan 已归档 [TT-3072] phase 3,见 `<instance-root>/archive/`) | ☐ | ☐ | |
|
||||
| 1.2 | 每个 `skills/<name>/` 目录恰好包含一个 `SKILL.md`(例外:`_shared/` 目录不含 `SKILL.md`,为共享引用文档目录) | ☐ | ☐ | |
|
||||
| 1.3 | 每个产物型 skill 都有配套 `checklists/<name>.md`(无清单的自检要求即为缺口) | ☐ | ☐ | |
|
||||
| 1.4 | `checklists/` 中无孤儿清单(存在清单但无任何 skill 引用) | ☐ | ☐ | |
|
||||
@@ -179,6 +179,7 @@ creating thin wrapper checklist files would add no value.
|
||||
| 8.5 | 防范范围收窄:明令禁止「只看重点/从简」类弱化措辞(IEEE 1028-2008 完整性) | ☐ | ☐ | |
|
||||
| 8.6 | 留痕:审计产物落盘到结构化文件,而非仅存于对话 | ☐ | ☐ | |
|
||||
| 8.7 | 闭环:存在重审循环与收敛/审批终止条件(ISO 19011:2018 跟踪与关闭) | ☐ | ☐ | |
|
||||
| 8.8 | 流程自身测试为绿:Orchestrator(bash 可用)在派发审计员**之前**机械运行流程自身的测试套件与守卫门(`bun run test:parallel` 全量分片 + `check:*` 守卫族,如 core-parity / encoding-health / derived-artifacts),并把命令、基线 SHA 与结果摘要落盘到 `<runs-root>/audit/reviews/audit-process/process-tests-green.md`(Tier 1);审计员(只读,无 bash)核对该记录存在于当前基线且为绿——任何红测试/红守卫本身即流程缺陷,按 findings 登记(缺陷逃逸案例:红测试存活 3 轮审计、无任何维度运行过测试套件,[TT-4787]) | ☐ | ☐ | 运行归 Orchestrator、核对归审计员(角色边界:`core/skills/_shared/review-orchestrator-rules.md` §No bash for Explorer sub-agents) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -116,8 +116,8 @@
|
||||
| 5.4 | 测试相互独立,可任意顺序运行,无共享可变状态 | ☐ | ☐ | |
|
||||
| 5.5 | Mock/Stub 的使用合理,模拟的外部行为与真实行为一致 | ☐ | ☐ | |
|
||||
| 5.6 | 测试命名清晰表达了测试场景和预期结果 | ☐ | ☐ | |
|
||||
| 5.7 | 本次变更涉及的测试已通过(`test:changed`,由 mechanical-green gate 机器判定,评审员引用 gate 结果即可)。全量套件(`test:parallel`)归 verify,不是代码评审门禁([org-internal #2598] 检查分层) | ☐ | ☐ | |
|
||||
| 5.8 | 评审发现的"dummy fixture / harness 默认值漂移"类问题,不能仅凭 `WAIVED` 处置:若漂移值是 harness 对**生产 CLI/配置默认值**的镜像(如 harness 旧 owner 默认 vs CLI 新 owner 默认这类 token 漂移),WAIVED 会把真实漂移放行到 post-merge([org-internal #3169] TST-F002 → 后续 [org-internal #3172] 才修)。处置前确认该值是否被生产路径读取;被读取则必须 FIX 或显式登记 TD | ☐ | ☐ | |
|
||||
| 5.7 | 本次变更涉及的测试已通过(`test:changed`,由 mechanical-green gate 机器判定,评审员引用 gate 结果即可)。全量套件(`test:parallel`)归 verify,不是代码评审门禁([TT-2598] 检查分层) | ☐ | ☐ | |
|
||||
| 5.8 | 评审发现的"dummy fixture / harness 默认值漂移"类问题,不能仅凭 `WAIVED` 处置:若漂移值是 harness 对**生产 CLI/配置默认值**的镜像(如 harness 旧 owner 默认 vs CLI 新 owner 默认这类 token 漂移),WAIVED 会把真实漂移放行到 post-merge([TT-3169] TST-F002 → 后续 [TT-3172] 才修)。处置前确认该值是否被生产路径读取;被读取则必须 FIX 或显式登记 TD | ☐ | ☐ | |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
> **权威源**:本文件判据逐行复制 `dag-pipeline/spec-04` §1 三张表
|
||||
> (含 `NFR:` 前缀 / 里程碑边 / 里程碑节点豁免与 `estimated_sessions` 判据)。
|
||||
> 若本文件与 spec-04 §1 不一致,以 spec-04 §1 为唯一权威源。
|
||||
> (`spec-0N` 前身为 `dag-pipeline/03-design-0N-*`,2026-08-21 [org-internal #3072] phase 3
|
||||
> (`spec-0N` 前身为 `dag-pipeline/03-design-0N-*`,2026-08-21 [TT-3072] phase 3
|
||||
> 升格迁移,旧名仅保留墓碑占位以维持旧 URL 可达。)
|
||||
|
||||
## TOPO — 拓扑维
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
2. **POST** 项在完成编码和所有验证命令后检查;
|
||||
3. 对"不通过"项必须在代码评审前修复;
|
||||
4. 无法满足的项标记 `[N/A: <原因>]`;
|
||||
5. **DAG 路由产物解析([org-internal #3072] phase 3 后唯一管线模式)**:DAG 运行不存在
|
||||
5. **DAG 路由产物解析([TT-3072] phase 3 后唯一管线模式)**:DAG 运行不存在
|
||||
legacy `{slug}/04-plan-*` / `{slug}/03-design-*` 页面,PRE-1~PRE-7、
|
||||
PRE-11、PRE-12、PRE-19、POST-15.1 引用的产物按 `implement`/`verify`
|
||||
SKILL 的 DAG-route read map 解析:工作项定义 → 冻结 DAG 副本
|
||||
@@ -68,17 +68,17 @@
|
||||
| ------ | -------------------------------------------------------------------------- | ---- | ------ | --- | ---- |
|
||||
| PRE-11 | 设计文档(wiki pages `{slug}/03-design-**`)已存在且包含本工作项涉及的全部组件设计 | ☐ | ☐ | ☐ | |
|
||||
| PRE-12 | 迭代计划(plan/)已存在且本工作项有明确的工作项 ID 和验收条件 | ☐ | ☐ | ☐ | |
|
||||
| PRE-13 | 评审门已收敛:DAG 路由下为 review-dag 单门收敛(`octopus review status --stage review-dag` 的 state 为 `success`,与 `pipeline-gate.md` DAG 路由变体一致);standalone 模式(bugfix/refactor/port)无上游评审门,标记 `[N/A: standalone 无上游评审]`(legacy design-space / iteration-plan 双门已随 [org-internal #3072] phase 3 归档) | ☐ | ☐ | ☐ | |
|
||||
| PRE-13 | 评审门已收敛:DAG 路由下为 review-dag 单门收敛(`octopus review status --stage review-dag` 的 state 为 `success`,与 `pipeline-gate.md` DAG 路由变体一致);standalone 模式(bugfix/refactor/port)无上游评审门,标记 `[N/A: standalone 无上游评审]`(legacy design-space / iteration-plan 双门已随 [TT-3072] phase 3 归档) | ☐ | ☐ | ☐ | |
|
||||
| PRE-14 | 合并前基准刷新:当前分支已 rebase 到目标分支(`git fetch origin && git rebase origin/main`),无合并冲突。若 rebase 引入新变更,重新运行 `bun typecheck && bun run test:parallel` 后再提交 | ☐ | ☐ | ☐ | |
|
||||
|
||||
### 5. UI 组件设计完整性(仅前端/UI 工作项)
|
||||
|
||||
| # | 检查项 | 通过 | 不通过 | N/A | 备注 |
|
||||
| ------ | -------------------------------------------------------------------------- | ---- | ------ | --- | ---- |
|
||||
| PRE-15 | 设计文档覆盖了组件的全部四种状态(Loading / Empty / Error / Success),每种状态有明确的渲染内容和触发条件(参见 `.octopus/archive/templates/design.md` §11.1,legacy 设计模板 [org-internal #3072] phase 3) | ☐ | ☐ | ☐ | |
|
||||
| PRE-16 | 设计文档覆盖了组件所需的全部交互行为:列表导航、焦点管理、键盘快捷键、展开/折叠、实时过滤(参见 `.octopus/archive/templates/design.md` §11.2,legacy 设计模板 [org-internal #3072] phase 3) | ☐ | ☐ | ☐ | |
|
||||
| PRE-17 | 设计文档覆盖了组件的全部可访问性要求:ARIA role/label、键盘可达、焦点环、对比度、色彩独立性(参见 `.octopus/archive/templates/design.md` §11.3,legacy 设计模板 [org-internal #3072] phase 3) | ☐ | ☐ | ☐ | |
|
||||
| PRE-18 | 设计文档已逐组件声明测试策略类型(render / source-verification / E2E / manual)。已知测试基础设施限制(Kobalte portal + happydom、路由上下文缺失等)已有对应替代方案标记(参见 `.octopus/archive/templates/design.md` §11.4,legacy 设计模板 [org-internal #3072] phase 3) | ☐ | ☐ | ☐ | |
|
||||
| PRE-15 | 设计文档覆盖了组件的全部四种状态(Loading / Empty / Error / Success),每种状态有明确的渲染内容和触发条件(参见 `.octopus/archive/templates/design.md` §11.1,legacy 设计模板 [TT-3072] phase 3) | ☐ | ☐ | ☐ | |
|
||||
| PRE-16 | 设计文档覆盖了组件所需的全部交互行为:列表导航、焦点管理、键盘快捷键、展开/折叠、实时过滤(参见 `.octopus/archive/templates/design.md` §11.2,legacy 设计模板 [TT-3072] phase 3) | ☐ | ☐ | ☐ | |
|
||||
| PRE-17 | 设计文档覆盖了组件的全部可访问性要求:ARIA role/label、键盘可达、焦点环、对比度、色彩独立性(参见 `.octopus/archive/templates/design.md` §11.3,legacy 设计模板 [TT-3072] phase 3) | ☐ | ☐ | ☐ | |
|
||||
| PRE-18 | 设计文档已逐组件声明测试策略类型(render / source-verification / E2E / manual)。已知测试基础设施限制(Kobalte portal + happydom、路由上下文缺失等)已有对应替代方案标记(参见 `.octopus/archive/templates/design.md` §11.4,legacy 设计模板 [TT-3072] phase 3) | ☐ | ☐ | ☐ | |
|
||||
| PRE-19 | 超过 3 个 MANUAL 类型的 AC 已标记为设计风险,并在 plan 中标注更高级测试基础设施依赖 | ☐ | ☐ | ☐ | |
|
||||
|
||||
---
|
||||
@@ -97,7 +97,7 @@
|
||||
| POST-6 | 若不得已偏离设计,有明确的注释标注原因和设计修正建议(含 ADR/amend 引用 — 不可仅写"偏离设计") | ☐ | ☐ | ☐ | |
|
||||
| POST-6.1 | 已用设计文档中的决策树/状态机/真值表,代入至少 2 组具体输入手工 trace 每条分支,确认代码输出与设计预期一致(尤其条件取反、`===` vs `!==`、状态翻转等易错点) | ☐ | ☐ | ☐ | |
|
||||
| POST-6.2 | 因 API 不兼容、上游限制或测试基础设施不足而延迟的项,已在代码中用 `[OPEN: <short-id>]` 标注(含延迟原因、影响范围、建议解决时机)。verify Phase 5.5 会为每个 `[OPEN]` 项在源票 `## TD 登记` 评论登记一行(registry-first,`ticket-lifecycle.md`;排期后才升格独立票)。禁止仅标注 `[OPEN]` 而不登记 | ☐ | ☐ | ☐ | |
|
||||
| POST-6.3 | 邻近配额([org-internal #3002] G3):本迭代触碰的区域(包/模块)若在源票 `## TD 登记` 中有适用行,已带走 ≥1 项一并处置(修复或带理由显式再延迟);无适用行时在报告记录 `0 applicable` | ☐ | ☐ | ☐ | |
|
||||
| POST-6.3 | 邻近配额([TT-3002] G3):本迭代触碰的区域(包/模块)若在源票 `## TD 登记` 中有适用行,已带走 ≥1 项一并处置(修复或带理由显式再延迟);无适用行时在报告记录 `0 applicable` | ☐ | ☐ | ☐ | |
|
||||
|
||||
### 5. 代码质量
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
| POST-10.4 | 多写操作(INSERT + UPDATE)用 `Database.transaction` 包裹保证原子性 | ☐ | ☐ | ☐ | |
|
||||
| POST-11 | 无硬编码凭据、密钥、内网地址或环境特定值 | ☐ | ☐ | ☐ | |
|
||||
| POST-11.1 | 提交前无法跟踪链接检查(单一事实来源:`code-review.md` SEC 3.7.1——`git diff --cached --diff-filter=T` 为空;判据以该条为准)| ☐ | ☐ | ☐ | |
|
||||
| POST-11.2 | 提交前已确认无进程/流程副产品混入暂存区(如 `.claim` 空文件、claim carrier、临时 pid/日志)——`git status` 逐条核对,`git add -A` 前先看 untracked 清单([org-internal #3169] 教训:`.claim` 空文件随 iter-0 混入,round-1 九维评审要求 `git rm`) | ☐ | ☐ | ☐ | |
|
||||
| POST-11.2 | 提交前已确认无进程/流程副产品混入暂存区(如 `.claim` 空文件、claim carrier、临时 pid/日志)——`git status` 逐条核对,`git add -A` 前先看 untracked 清单([TT-3169] 教训:`.claim` 空文件随 iter-0 混入,round-1 九维评审要求 `git rm`) | ☐ | ☐ | ☐ | |
|
||||
| POST-12 | 无注释掉的代码块或 `console.log` 调试语句 | ☐ | ☐ | ☐ | |
|
||||
| POST-13 | 无 `as any` 类型断言绕过类型检查(生产代码必须保有完整类型安全) | ☐ | ☐ | ☐ | |
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ Upstream Artifact Existence 与 Upstream Review Convergence 检查
|
||||
`success`(替代 design-space + iteration-plan 双门;任务工单
|
||||
不重跑单门,只核对其已收敛)
|
||||
- [ ] (仅任务工单)票 body `## 父级 / Parent` 指向 DAG 父级
|
||||
(`Kind/Epic` 或 `Kind/Feature`,[org-internal #3061] 阶段 2),
|
||||
(`Kind/Epic` 或 `Kind/Feature`,[TT-3061] 阶段 2),
|
||||
Step 0 解析到 `dag.task_route`(entry `implement`),不继承
|
||||
`dag.route`
|
||||
- [ ] 跨节点依赖由 DAG 拓扑承担:节点 ready 以其全部跨 session 上游
|
||||
@@ -34,7 +34,7 @@ review-dag)直至收敛;DAG 副本缺失或未冻结 → 回到 `analyze-dag
|
||||
- [ ] standalone bugfix:repro notes wiki page `{slug}/repro-notes` 存在且含环境快照(via `wiki 读写 API(见 TERMINOLOGY)`)
|
||||
- [ ] 验收条件可解析:来自请求/工单 body 或节点 AC(等价的验收条件文档,via `wiki 读写 API(见 TERMINOLOGY)` / `工单 API(见 TERMINOLOGY)get`)
|
||||
|
||||
> Legacy([org-internal #3072] phase 3,2026-08-21 归档):requirements/design/plan baseline
|
||||
> Legacy([TT-3072] phase 3,2026-08-21 归档):requirements/design/plan baseline
|
||||
> 页(`{slug}/02-requirements-index` / `{slug}/03-design-index` /
|
||||
> `{slug}/04-plan-index` / `{slug}/04-plan-05-acceptance-criteria`)与
|
||||
> design-space / iteration-plan 双门收敛检查随 legacy 管线归档
|
||||
@@ -65,10 +65,10 @@ review-dag)直至收敛;DAG 副本缺失或未冻结 → 回到 `analyze-dag
|
||||
|
||||
## PR 准入(pr-admission)
|
||||
|
||||
> 纪律:`core/rules/ticket-lifecycle.md` PR 准入节(TD-678 / [org-internal #3881] / [org-internal #4425])。
|
||||
> 纪律:`core/rules/ticket-lifecycle.md` PR 准入节(TD-678 / [TT-3881] / [TT-4425])。
|
||||
|
||||
- [ ] PR 标题符合 `[slug][iter-N] type(scope): 描述` 格式
|
||||
- [ ] PR 正文含变更清单 + 自测结果 + 关联合规(关联 issue 引用,如 `Closes #N`;数字后须接 ASCII 标点或行尾——紧跟全角标点会破坏 Gitea 自动关闭,PR [org-internal #3882] 实例)
|
||||
- [ ] PR 正文含变更清单 + 自测结果 + 关联合规(关联 issue 引用,如 `Closes #N`;数字后须接 ASCII 标点或行尾——紧跟全角标点会破坏 Gitea 自动关闭,PR [TT-3882] 实例)
|
||||
- [ ] 交付推送前本地验证已绿:`<harness-package>` 下 `bun run test:changed` 全绿 + `bun typecheck` 0 error(WIP 备份推送不受此门约束——分支裸推零 CI,交付信号是完成回报而非推送)
|
||||
- [ ] 分支已推送 origin;PR **未**由本会话自行创建(由编排按容量串行开启,一次一张、双绿并入再开下一张)
|
||||
- [ ] 交付报告已发(branch= 分支名 / 改动文件清单 / 自测结果 / verify 与 risk 回执)
|
||||
@@ -81,7 +81,7 @@ review-dag)直至收敛;DAG 副本缺失或未冻结 → 回到 `analyze-dag
|
||||
> 状态跃迁),不得等到技能退出边界。规则:`core/rules/issue-checklist-sync.md`。
|
||||
|
||||
- [ ] 若存在 source issue:其 checklist 已按同步点表渐进勾选(DAG 冻结、iteration commit、PR 创建、review PASS、CI 跃迁、verify 终扫),无陈旧 `- [ ]` 项
|
||||
- [ ] 若为 incident / standalone-bugfix 流程:issue 含 `## 当前状态` live-status 小节,且 PR / review / CI 行已随跃迁更新([org-internal #1689])
|
||||
- [ ] 若为 incident / standalone-bugfix 流程:issue 含 `## 当前状态` live-status 小节,且 PR / review / CI 行已随跃迁更新([TT-1689])
|
||||
- [ ] 过程性 AC(如"连续 N 次绿")的进度注记已更新(带 run 编号)
|
||||
- [ ] 遗留项(未勾选)均有 `(Deferred: ...)` 或 `(Pending: ...)` 注记
|
||||
- [ ] verify PASS 时 `## 当前状态` 小节已折叠进 checklist 注记并移除
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
| 2.1 | 重构目标明确(哪种变换,为什么) | ☐ | ☐ | |
|
||||
| 2.2 | 步骤分解 ≤ 10 步 | ☐ | ☐ | |
|
||||
| 2.3 | 不存在范围蔓延(未在同一重构中混入新功能或 Bug 修复) | ☐ | ☐ | |
|
||||
| 2.4 | 若重构涉及身份/owner token 改名(org、账号、邮箱、域名前缀):已先产出"不改清单"——OS 账号、个人邮箱、历史记录归属、dummy fixture 等非组织身份引用逐类明确保留,再执行机械替换([org-internal #3169] 教训:D1 缺此边界 → round-1 15 MAJOR) | ☐ | ☐ | |
|
||||
| 2.4 | 若重构涉及身份/owner token 改名(org、账号、邮箱、域名前缀):已先产出"不改清单"——OS 账号、个人邮箱、历史记录归属、dummy fixture 等非组织身份引用逐类明确保留,再执行机械替换([TT-3169] 教训:D1 缺此边界 → round-1 15 MAJOR) | ☐ | ☐ | |
|
||||
|
||||
---
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
| 4.4 | 测试覆盖率未下降(±1%) | ☐ | ☐ | |
|
||||
| 4.5 | 无新增或修改的测试(重构不应改变测试中的断言逻辑) | ☐ | ☐ | |
|
||||
| 4.6 | 若重构改变了对外可见字符串(stage 名称、tool description、错误消息等),对应的 snapshot 已通过 `bun test --update-snapshots` 更新 | ☐ | ☐ | |
|
||||
| 4.7 | 若重构变更了身份/owner token:残留扫描守卫(如 `script/verify-urls.ts`)已做**语义正反验证**——搜索模式指向**旧** token(旧 owner 前缀的 URL 形态),且已知新 token(新 owner 前缀的 URL 形态)与真实旧残留各跑一次,确认守卫对"合规新 URL"不误报、对"真实残留"不漏报([org-internal #3169] 教训:D5 模式被翻转 → 守卫对新 URL 误报、对旧残留失明) | ☐ | ☐ | |
|
||||
| 4.7 | 若重构变更了身份/owner token:残留扫描守卫(如 `script/verify-urls.ts`)已做**语义正反验证**——搜索模式指向**旧** token(旧 owner 前缀的 URL 形态),且已知新 token(新 owner 前缀的 URL 形态)与真实旧残留各跑一次,确认守卫对"合规新 URL"不误报、对"真实残留"不漏报([TT-3169] 教训:D5 模式被翻转 → 守卫对新 URL 误报、对旧残留失明) | ☐ | ☐ | |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Release 检查清单
|
||||
|
||||
> 发版前自检。Release Manager 在 Phase 1 和 Phase 6 完整过一遍。
|
||||
> 发版前自检。Producer (Worker) 在 Phase 1 和 Phase 6 完整过一遍。
|
||||
|
||||
> **维度命名空间(dimension namespace)**: 本清单中的维度代码(如 TST/BEH/GATE/REG)是**清单局部(checklist-local)**标识符,仅在本文档内唯一;其他清单可能对相同字母串绑定不同概念(如 code-review.md 的 TST=Test Quality、verification.md 的 TST=Test Suite Completeness、port.md 的 TST=Test Porting)。跨清单引用时必须带清单限定(如 code-review.md TST 5.8),不得使用裸代码。
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
| 1.11 | 已检查 merged workflow/* 分支与关联 worktree 在合并后已清理(本地分支删除 + worktree 移除) | ☐ | ☐ | |
|
||||
| 1.12 | 周期时长和团队规模已记录(压缩周期 = 质量风险,单点故障) | ☐ | ☐ | |
|
||||
| 1.13 | 范围估算验证:triage/scope 声明前已统计各标签下的 issue 数量(如 `Status/Blocked`、`Kind/*`、`Priority/*`),并与之前声明对比,偏差 >20% 标注为估算偏差 | ☐ | ☐ | |
|
||||
| 1.14 | 门缺陷逃逸分析已运行(§2.8 escape-rate 单指标,[org-internal #3061]):各 gate 的 clean runs / escapes / escape_rate 已统计,UNDER-POWERED(≥0.3)门已标注并回馈 §2.9 pre-flight(gate-trim 元进程已退役,[org-internal #3072] phase 3) | ☐ | ☐ | |
|
||||
| 1.14 | 门缺陷逃逸分析已运行(§2.8 escape-rate 单指标,[TT-3061]):各 gate 的 clean runs / escapes / escape_rate 已统计,UNDER-POWERED(≥0.3)门已标注并回馈 §2.9 pre-flight(gate-trim 元进程已退役,[TT-3072] phase 3) | ☐ | ☐ | |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -119,9 +119,9 @@
|
||||
| # | 检查项 | 通过 | 不通过 | 备注 |
|
||||
| --- | --------------------------------------------------------------------- | ---- | ------ | ---- |
|
||||
| 8.1 | 本迭代全部 UNVERIFIABLE / ACCEPTED_RISK / `[OPEN]` 项均已登记为源票 `## TD 登记` 评论中的行(registry-first,`ticket-lifecycle.md`;`filing.sprint-mode: true` 期间禁止升格独立票) | ☐ | ☐ | |
|
||||
| 8.2 | 每行含 `TD-NNN`、type、Severity、origin、一句话摘要与可客观验证的 Reactivation Trigger;TD-NNN 为注册期分配——经 `script/td-alloc.sh` 从号段台账(TD allocation ledger,常设 tracker)取号,任何分配必须先落台账 td-alloc 评论([org-internal #3322] 互斥) | ☐ | ☐ | |
|
||||
| 8.2 | 每行含 `TD-NNN`、type、Severity、origin、一句话摘要与可客观验证的 Reactivation Trigger;TD-NNN 为注册期分配——经 `script/td-alloc.sh` 从号段台账(TD allocation ledger,常设 tracker)取号,任何分配必须先落台账 td-alloc 评论([TT-3322] 互斥) | ☐ | ☐ | |
|
||||
| 8.3 | 两处登记的 `TD-NNN` 标识一致,且每项都有可客观验证的 Reactivation Trigger | ☐ | ☐ | |
|
||||
| 8.4 | 邻近配额复核([org-internal #3002] G3):报告含本迭代触碰区域的登记册带走情况(consumed/applicable,或 `0 applicable`);与本 run 的债务配额记录一致(legacy roadmap 状态追踪表已归档,[org-internal #3072] phase 3) | ☐ | ☐ | |
|
||||
| 8.4 | 邻近配额复核([TT-3002] G3):报告含本迭代触碰区域的登记册带走情况(consumed/applicable,或 `0 applicable`);与本 run 的债务配额记录一致(legacy roadmap 状态追踪表已归档,[TT-3072] phase 3) | ☐ | ☐ | |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Artifact-Index Guards (mandatory)
|
||||
|
||||
> Check-mechanized (injection-budget batch-3, [org-internal #3699]): guards
|
||||
> Check-mechanized (injection-budget batch-3, [TT-3699]): guards
|
||||
> 1-3's checkable invariants run in the repo's artifact-index-check script
|
||||
> (`<artifact-index-check-cmd> <ticket>`, see the term mapping; exit 4 =
|
||||
> violation, `--json` summary; tolerant of wild archive-marker dialects).
|
||||
@@ -16,7 +16,7 @@
|
||||
Before creating a `## 工件索引` comment, scan the issue's existing comments
|
||||
for the legacy prefix `## Pipeline 工件追踪表`. If found, UPGRADE it
|
||||
in place (edit, not create) and rename. NEVER create a second index comment
|
||||
(DEFECT-1 / [org-internal #1924]). Mechanized: reports the comment_id to edit.
|
||||
(DEFECT-1 / [TT-1924]). Mechanized: reports the comment_id to edit.
|
||||
|
||||
### 2. Never-duplicate invariant (single-comment)
|
||||
|
||||
|
||||
@@ -40,9 +40,9 @@ UI's "auto-accept permissions" toggle (browser-local, not the project
|
||||
> fix this table. `merge-pr` is excluded from default/preset `stages` arrays
|
||||
> (not structurally blocked; explicitly adding it is not recommended).
|
||||
> Legacy stage retirement (12 → 5): the phase-3 retirement ruling doc
|
||||
> (Tier-2 reference, reachable via the ticket backend).
|
||||
> (instance detail (in the consuming instance)).
|
||||
|
||||
Config shape: `"auto_approve": { "stages": ["review-code", "verify"], "stageless": false }` — `stages` empty (`[]`) = all manual; `stageless: true` also auto-approves questions called without a stage. Absent block defaults to `{ stages: ["review-code", "verify", "audit-process"], stageless: false }`; the removed `enabled` field migrates on load (mapping: Tier-2 reference page `rules/auto-approve-detail`). Presets (`safe`/`full`/`off`/`show`): same reference page — `full` never includes `merge-pr`.
|
||||
Config shape: `"auto_approve": { "stages": ["review-code", "verify"], "stageless": false }` — `stages` empty (`[]`) = all manual; `stageless: true` also auto-approves questions called without a stage. Absent block defaults to `{ stages: ["review-code", "verify", "audit-process"], stageless: false }`; the removed `enabled` field migrates on load (mapping: instance detail page `rules/auto-approve-detail`). Presets (`safe`/`full`/`off`/`show`): same reference page — `full` never includes `merge-pr`.
|
||||
|
||||
### Stage matching behavior
|
||||
|
||||
@@ -55,7 +55,7 @@ Config shape: `"auto_approve": { "stages": ["review-code", "verify"], "stageless
|
||||
Check logic: the harness 内建的问询与自动批准判定模块
|
||||
(resolveAutoApproveDecision).
|
||||
|
||||
### Live-gate degradation chain ([org-internal #3531])
|
||||
### Live-gate degradation chain ([TT-3531])
|
||||
|
||||
An auto-approved question is NOT consumed instantly: L1 — a live human
|
||||
watching the session (SSE declaration / fresh presence ping) answers within
|
||||
@@ -73,7 +73,7 @@ before the gate runs (iron law).
|
||||
|
||||
### Mandatory destructive list (业务决策类问询强制清单)
|
||||
|
||||
Origin: [org-internal #3223] — a stage whitelist auto-answered two
|
||||
Origin: [TT-3223] — a stage whitelist auto-answered two
|
||||
irreversible production data changes because nothing marked them
|
||||
`destructive`. A stage whitelist grants "execution gates may proceed
|
||||
uninterrupted"; it must NEVER grant "business decisions may be
|
||||
@@ -87,8 +87,7 @@ is never a substitute for human confirmation of these categories.**
|
||||
1. **Merge / release landing** — merging a PR to main, cutting a tag or
|
||||
release, deploying/promoting to production (server-side auto-merge is a
|
||||
human-configured policy robot, never agent self-answer latitude; kill
|
||||
switch: the auto-merge-low-risk runbook, Tier-2 reference via the ticket
|
||||
backend).
|
||||
switch: the auto-merge-low-risk runbook, instance detail (in the consuming instance)).
|
||||
2. **Production database writes** — upsert/update/delete against production
|
||||
data stores, production data migrations, live-data backfills.
|
||||
3. **Billing / plan changes** — plan or tier migration, pricing/concurrency
|
||||
|
||||
@@ -40,7 +40,8 @@ error, returns empty, or you cannot otherwise access a required resource, you
|
||||
MUST report the failure honestly. NEVER fabricate, invent, or hallucinate a
|
||||
plausible-looking result to fill the gap.
|
||||
|
||||
- An honest "I could not call `gitea_wiki__get_page`, so I cannot review
|
||||
- An honest "I could not reach the wiki read API (`GET
|
||||
<gitea-base-url>/api/v1/repos/{owner}/{repo}/wiki/pages`), so I cannot review
|
||||
dimension Y" is always correct. An honest failure beats a confident fiction.
|
||||
- Producing a complete, specific-looking structured result — review JSON with
|
||||
findings, severity levels, and file references, all invented — without a
|
||||
@@ -51,6 +52,7 @@ plausible-looking result to fill the gap.
|
||||
contents, API responses, search hits, metrics. If the tool did not return
|
||||
it, you do not know it — say so.
|
||||
|
||||
Origin: [org-internal #2115] root cause 5 / [org-internal #2118] — deepseek-v4-flash reviewers fabricated
|
||||
full review JSON when the `gitea_wiki__*` tools were unavailable to subagents.
|
||||
Origin: [TT-2115] root cause 5 / [TT-2118] — deepseek-v4-flash reviewers fabricated
|
||||
full review JSON when the wiki tool surface (MCP tooling at the time, now
|
||||
retired) was unavailable to subagents.
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ NOT grep + read whole files to reconstruct relationships.
|
||||
The main checkout's `.codegraph/` indexes ONLY that tree. A git worktree lives
|
||||
outside the repo path, so nearest-`.codegraph/` resolution finds nothing under
|
||||
it — graph queries in a workflow worktree silently degrade to grep+read
|
||||
(the [org-internal #2561] / TD-006 gap).
|
||||
(the [TT-2561] / TD-006 gap).
|
||||
|
||||
- `script/session-worktree.sh create` and `script/scratch-worktree.sh create`
|
||||
build a per-worktree index automatically: `codegraph init -i <path>` runs in
|
||||
|
||||
@@ -6,13 +6,13 @@ Context compaction keeps long pipelines inside the model's context window.
|
||||
Two mechanisms exist:
|
||||
|
||||
1. **Stage-boundary compaction** (main session / orchestrator) —
|
||||
capacity-driven [org-internal #2601]: compact at a clean stage boundary
|
||||
capacity-driven [TT-2601]: compact at a clean stage boundary
|
||||
ONLY when a capacity trigger holds (below), not merely because the
|
||||
boundary was reached.
|
||||
2. **Round-boundary compaction** (multi-round reviews) — compact at every
|
||||
review round ≥ 2, after the round's state is persisted.
|
||||
|
||||
### Stage-boundary compaction (capacity-driven, [org-internal #2601])
|
||||
### Stage-boundary compaction (capacity-driven, [TT-2601])
|
||||
|
||||
The main session orchestrates the whole pipeline while delegating stages to
|
||||
subagents, but still accumulates their result summaries, planning reasoning,
|
||||
@@ -35,16 +35,16 @@ A trigger holding → compact at the NEAREST clean boundary. No trigger → KEEP
|
||||
the context: preserved working context is worth more than the tokens it costs.
|
||||
|
||||
**Mixed capacity threshold — min(water_level, absolute cap)
|
||||
[org-internal #3321] / TD-434]**: the capacity threshold is
|
||||
[TT-3321] / TD-434]**: the capacity threshold is
|
||||
`min(context × water_level, compaction.max_context_tokens)` — whichever is
|
||||
LOWER (`max_context_tokens` default 100_000; `0` restores pure water_level
|
||||
semantics [org-internal #3342]). On large windows the 100k cap binds first.
|
||||
semantics [TT-3342]). On large windows the 100k cap binds first.
|
||||
Measurement basis: the provider's REAL reported usage (input tokens), not
|
||||
local estimates; the rendered guidance and the Trigger A/B overflow paths
|
||||
resolve the same normalized values (harness 内建的压缩引导模块, see the
|
||||
instance term mapping).
|
||||
|
||||
**Sub-session posture [org-internal #3321]**: Explorers compact by returning
|
||||
**Sub-session posture [TT-3321]**: Explorers compact by returning
|
||||
promptly, persisting only what their skill protocol REQUIRES (review findings
|
||||
JSON to the run workspace reviews directory). Workers persist outputs to
|
||||
Tier 1 BEFORE finishing. The parent context is where the mixed threshold
|
||||
@@ -52,8 +52,7 @@ applies. Tier 1 boundary: two-tier-artifacts rule.
|
||||
|
||||
**Short runs target zero intra-run compaction** — an implement →
|
||||
review-code → verify run fits one window; clean boundaries do not compact
|
||||
without a trigger. (Rationale + retired legacy stages: Tier-2 reference page
|
||||
`rules/compact-detail`, reachable via the ticket backend.)
|
||||
without a trigger. (Rationale + retired legacy stages: instance detail page `rules/compact-detail`, reachable via the ticket backend.)
|
||||
|
||||
Clean boundaries where triggers are evaluated (live skills):
|
||||
|
||||
@@ -74,7 +73,7 @@ DAG-routed runs, the latest review pages, or the DoD matrix
|
||||
(`{slug}/05-verify-*`) — to recover the current slug, stage, and outstanding
|
||||
items. Do not rely on the compacted summary alone.
|
||||
|
||||
**Identity verification precedes re-orientation [org-internal #2459].**
|
||||
**Identity verification precedes re-orientation [TT-2459].**
|
||||
Every compacted summary opens with a harness-injected `### Session Identity`
|
||||
card (agent, role/mode/ticket, CORE artifact rows, role re-read set),
|
||||
rendered from role-yaml `compact.preserve` lists and issue CORE rows by the
|
||||
@@ -99,7 +98,7 @@ The `compact` tool rejects calls made too soon after the previous one
|
||||
turns); no boundary type is exempt. Beyond `insufficient_turns` the tool has
|
||||
more guard outcomes (`min_interval`, `no_model`, `circuit_breaker_open`,
|
||||
`disabled` — rejected; `compaction_in_progress`, `deduplicated` — deferred;
|
||||
full table: Tier-2 reference page `rules/compact-detail`, reachable via the
|
||||
full table: instance detail page `rules/compact-detail`, reachable via the
|
||||
ticket backend). All are accept-and-continue: never retry past a guard,
|
||||
never work around the dedup/breaker state. A boundary whose compaction was
|
||||
rejected or deferred simply keeps its context; the persisted artifacts still
|
||||
|
||||
@@ -11,16 +11,16 @@ point and see exactly what is done, in progress, and deferred.
|
||||
|
||||
| When | Who | What |
|
||||
|------|-----|------|
|
||||
| After the DAG artifact is frozen (`review-dag` PASS + freeze confirmation per `analyze-dag/SKILL.md` §Output & Lifecycle step 2, [org-internal #3379]) | Aggregator agent | Convert the source Epic's draft acceptance criteria into a formal checklist; annotate requirement-covered items `_(DAG frozen: {epic-slug}/dag v1)_` |
|
||||
| After the DAG artifact is frozen (`review-dag` PASS + freeze confirmation per `analyze-dag/SKILL.md` §Output & Lifecycle step 2, [TT-3379]) | Aggregator agent | Convert the source Epic's draft acceptance criteria into a formal checklist; annotate requirement-covered items `_(DAG frozen: {epic-slug}/dag v1)_` |
|
||||
| After each iteration commit (`implement` Phase 4.5) | Developer | Check off items delivered by this iteration |
|
||||
| After a PR is created | Developer | Append a `## 当前状态` live-status section (or update it) with PR number + mergeable; in an Epic task list, append the PR reference to the corresponding row |
|
||||
| After code review converges (`review-code` PASS, Phase E) | Orchestrator | Check off review-related items; annotate `_(reviewed: round N PASS)_`; update the `## 当前状态` review row; label the PR `ready-to-merge` — keep-mergeable automation takes over (hand-written keep-mergeable commits are retired) |
|
||||
| On CI key state transitions (first green / failure / cumulative goal reached) | Verifier or Developer | Update the process-type AC (e.g. "N consecutive green runs") progress note in the issue; record the run number |
|
||||
| At `verify` Phase 5.6 (final sweep before PASS) / issue close | Closing agent (Verifier on the primary path; otherwise the last role that closes the issue) | Final sweep — every remaining item gets annotated; **archive-at-close**: fold `## 当前状态`, then mark the `## 工件索引` comment archived per the artifact-index-guards rule guard #3 (see「归档动作」below) |
|
||||
|
||||
> Historical ([org-internal #3072] phase 3): the requirements/design/plan exit sync points
|
||||
> were archived with their skills (detail: Tier-2 reference page
|
||||
> `rules/issue-checklist-sync-detail`, reachable via the ticket backend).
|
||||
> Historical ([TT-3072] phase 3): the requirements/design/plan exit sync points
|
||||
> were archived with their skills (detail: instance detail page
|
||||
> `rules/issue-checklist-sync-detail`, in the consuming instance).
|
||||
|
||||
Between sync points the checklist stays as-is. **PR / review / CI
|
||||
transitions** MUST also be visible via the live status note below — the
|
||||
@@ -32,12 +32,12 @@ For flows with externally visible transitions between skill exits —
|
||||
standalone bugfix, incident response, long-running reviews — maintain a short
|
||||
live status table near the top of the issue body, updated in place via the
|
||||
ticket-backend issue-update API at the transition moment (closes the
|
||||
stale-issue gap [org-internal #1668]/[org-internal #1689]]).
|
||||
stale-issue gap [TT-1668]/[TT-1689]]).
|
||||
|
||||
All roles use the literal heading `## 当前状态` (no suffix). If an issue carries
|
||||
a legacy variant (e.g. `## 当前状态 (live)` from [org-internal #1668]), normalize it to
|
||||
a legacy variant (e.g. `## 当前状态 (live)` from [TT-1668]), normalize it to
|
||||
`## 当前状态` at the first transition touched. Example table + legacy-variant
|
||||
list: Tier-2 reference page `rules/issue-checklist-sync-detail`, reachable
|
||||
list: instance detail page `rules/issue-checklist-sync-detail`, reachable
|
||||
via the ticket backend.
|
||||
|
||||
Rules:
|
||||
@@ -57,15 +57,15 @@ Rules:
|
||||
- At verify PASS / issue close, fold the table's content into checklist
|
||||
annotations and remove the section (see the「归档动作」section below).
|
||||
|
||||
### Automated sync ([org-internal #1833], timer-polled since [org-internal #2813])
|
||||
### Automated sync ([TT-1833], timer-polled since [TT-2813])
|
||||
|
||||
PR / review / CI status-row transitions are automated by the `status-sync`
|
||||
poller (deployed as a host timer, every 5 min; event sources + latency table
|
||||
on the Tier-2 reference page `rules/issue-checklist-sync-detail`, reachable
|
||||
on the instance detail page `rules/issue-checklist-sync-detail`, reachable
|
||||
via the ticket backend). Roles do NOT hand-write those three row types. A PR
|
||||
body may carry several close refs (batch PRs, [org-internal #3731]
|
||||
body may carry several close refs (batch PRs, [TT-3731]
|
||||
`land-batch`): rows fan out to EVERY referenced issue
|
||||
(`parseClosesFixesWide` — [org-internal #3867], merged 2026-08-31) — Chinese 关闭/修复 refs
|
||||
(`parseClosesFixesWide` — [TT-3867], merged 2026-08-31) — Chinese 关闭/修复 refs
|
||||
drive rows too, even though the ticket backend never auto-closes those
|
||||
keywords. The remaining sync points (checklist annotations at skill exits,
|
||||
`## 当前状态` creation, deferral/pending marking, section fold-at-close) are
|
||||
@@ -80,8 +80,7 @@ deduplicated `[status-sync-cron]` issue.
|
||||
Pipeline mode has natural sync points at skill exits; standalone bugfix and
|
||||
incident flows do NOT — the only boundaries are commit → PR → review → CI →
|
||||
merge, and EACH is a sync point with the same annotations as the progressive
|
||||
table above (full table: Tier-2 reference page
|
||||
`rules/issue-checklist-sync-detail`, reachable via the ticket backend): fix
|
||||
table above (full table: instance detail page `rules/issue-checklist-sync-detail`, reachable via the ticket backend): fix
|
||||
commit → tick fix-delivered ACs `_(commit {sha}: file)_`; PR → open/update
|
||||
`## 当前状态`; review convergence → tick review ACs + review row; CI
|
||||
transitions → process-AC progress with run number; verify PASS / close →
|
||||
@@ -108,7 +107,7 @@ For tickets routed through the DAG pipeline (see workflow-routing rule
|
||||
comment (single-comment invariant). The body aggregator table is kept as a
|
||||
historical snapshot at close and does NOT carry ARCHIVE.
|
||||
|
||||
### Kind/MVP tickets — exemption ([org-internal #3061])
|
||||
### Kind/MVP tickets — exemption ([TT-3061])
|
||||
|
||||
`Kind/MVP` tickets run the interactive no-pipeline mode: no stage exits →
|
||||
**nothing to sync**, no `## 当前状态` section (no PR/review/CI rows until
|
||||
@@ -137,7 +136,7 @@ non-checklist content. PR / review / CI transitions ALSO go into the
|
||||
|
||||
### 归档动作(issue 关闭 = 归档)
|
||||
|
||||
**生命周期 = 工单生命周期**([org-internal #1929]):文档生命周期与源 issue 绑定 —— verify PASS → issue 关闭 = 归档。Tier-2 工件库无独立生命周期。
|
||||
**生命周期 = 工单生命周期**([TT-1929]):文档生命周期与源 issue 绑定 —— verify PASS → issue 关闭 = 归档。Tier-2 工件库无独立生命周期。
|
||||
|
||||
归档是 **显式动作**,由关闭 issue 的 agent 执行:主路径为 Verifier 在 `verify` Phase 5.6;路径跳过 verify 时(audit-only、文档类、standalone/bugfix)由关闭 issue 的 role 代为执行。无论哪个 actor,均遵循 artifact-index-guards 规则 guard #3(机制以共享 write-patterns Pattern 10 为准)。动作序列:
|
||||
|
||||
@@ -146,7 +145,7 @@ non-checklist content. PR / review / CI transitions ALSO go into the
|
||||
3. **标记 `## 工件索引` 归档**:按共享 write-patterns Pattern 10 Archive-at-close 原位 edit(机制以 Pattern 10 为准)。横幅日期以实际关闭日为准。
|
||||
4. **关闭 issue**:PR body 的 `Closes #N` 在 merge 时自动关闭;无 PR 的流程由 **关闭 issue 的 agent** 执行工单后端的 issue-close API 完成闭环。
|
||||
|
||||
约束([org-internal #1928] 设计约束;机制细节以共享 write-patterns Pattern 10 Archive-at-close 为准,此处不重复):
|
||||
约束([TT-1928] 设计约束;机制细节以共享 write-patterns Pattern 10 Archive-at-close 为准,此处不重复):
|
||||
|
||||
- **L 级大件(>~300 行)留 Tier-2 工件库不删除** —— 页面与位置列 URL 保持不动(稳定 URL 供历史与共享契约引用)。
|
||||
- **索引/状态/归档判定全部收敛到 issue** —— Tier-2 工件库无独立生命周期;归档标记只落在 `## 工件索引` 评论。
|
||||
|
||||
@@ -14,7 +14,7 @@ regression-test follow-up, or any parent/child breakdown — the issues MUST be
|
||||
cross-linked:
|
||||
|
||||
- **Parent issue**: after creating all children, update the parent body so its
|
||||
task list references each child by `#<number>` (e.g. `- [ ] [org-internal #1556] — [P0] ...`).
|
||||
task list references each child by `#<number>` (e.g. `- [ ] [TT-1556] — [P0] ...`).
|
||||
The ticket backend renders these as clickable links and auto-generates a
|
||||
back-reference on each child's timeline.
|
||||
- **Child issue**: its body MUST contain a `## 父级 / Parent` section referencing
|
||||
@@ -25,7 +25,7 @@ cross-linked:
|
||||
### Issue ↔ Tier-2 artifact (pipeline traceability)
|
||||
|
||||
When a production skill (`analyze-dag`, publishing the `{epic-slug}/dag`
|
||||
artifact; historically the pre-[org-internal #3072] producer skills) publishes
|
||||
artifact; historically the pre-[TT-3072] producer skills) publishes
|
||||
an artifact to the Tier-2 artifact library, the link to the source issue is
|
||||
only **half-built** — the library's index page links forward to the issue,
|
||||
but the issue has no link back to the library. A stakeholder opening the
|
||||
@@ -44,7 +44,7 @@ After publishing, the skill MUST complete the reverse link on the source issue:
|
||||
reads the 工件索引 comment and fetches every CORE row's 位置 (shared
|
||||
read-patterns doc Pattern 6), instead of hard-coded library paths. Skills'
|
||||
re-read instructions therefore point at the index.
|
||||
- **Archive-at-close(归档动作, [org-internal #1929]/[org-internal #1928])** — issue 关闭即归档;Tier-2 工件库无独立
|
||||
- **Archive-at-close(归档动作, [TT-1929]/[TT-1928])** — issue 关闭即归档;Tier-2 工件库无独立
|
||||
生命周期。`ARCHIVE` is not just a per-row re-read priority: at issue close the
|
||||
whole index is marked archived by the closing agent (Verifier at `verify`
|
||||
Phase 5.6 on the primary path; otherwise the Orchestrator / last-role that
|
||||
@@ -56,11 +56,11 @@ After publishing, the skill MUST complete the reverse link on the source issue:
|
||||
- **Sync the issue's checklist** per the issue-checklist-sync rule for the
|
||||
matching exit point (live: the DAG-freeze sync point after `review-dag`
|
||||
PASS; the legacy requirements-exit / design-exit / plan-exit points were
|
||||
retired with their skills, [org-internal #3072] phase 3).
|
||||
retired with their skills, [TT-3072] phase 3).
|
||||
- Skip if no source issue exists (no `Closes #N` / `Fixes #N` / roadmap chunk
|
||||
mapping ties this slug to an issue).
|
||||
|
||||
**Size/S & Size/M exception ([org-internal #1832]) — RETIRED (2026-08-21, [org-internal #3072]
|
||||
**Size/S & Size/M exception ([TT-1832]) — RETIRED (2026-08-21, [TT-3072]
|
||||
phase 3)**: retired with the legacy producer skills and the `sizing:` block.
|
||||
Historical indexes pointing at in-issue artifacts (`位置 = #comment-{id}`)
|
||||
remain valid, readable locations; new artifacts publish where their live
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Session Scope Guard (mandatory)
|
||||
|
||||
> Enforcement layer: precheck-mechanized (injection-budget batch-2,
|
||||
> [org-internal #3667]) — pre-flight sources 1-3 below live in the repo's
|
||||
> [TT-3667]) — pre-flight sources 1-3 below live in the repo's
|
||||
> session-conflicts script, source 4 in the claim script's compare-and-swap.
|
||||
> This file is the normative definition, NOT part of any `agents_md`
|
||||
> injection whitelist since 2026-08-29 — do not re-add; the checks run at
|
||||
@@ -11,8 +11,7 @@
|
||||
|
||||
Standalone and ticket-seeded sessions run without a pipeline around them —
|
||||
no plan, no reviewer keeping them inside their work item. When such a
|
||||
session hits a test failure NOT caused by its own change ([org-internal
|
||||
[org-internal #1803]], via [org-internal #1753]/[[org-internal #1744]]), it tends to fix the foreign
|
||||
session hits a test failure NOT caused by its own change ([TT-1803], via [TT-1753]/[TT-1744]), it tends to fix the foreign
|
||||
failure in place (drifting off-task), and sessions seeded for the same issue
|
||||
collide on the same shared flaky test.
|
||||
|
||||
@@ -48,17 +47,17 @@ on ANY source → the ticket is already owned: ABORT (or, for a DEAD claim,
|
||||
take over via the mechanized channel below; otherwise coordinate on the
|
||||
issue), never silently start a second owner.
|
||||
|
||||
**Mechanized ([org-internal #3667])**: the repo's session-conflicts script
|
||||
**Mechanized ([TT-3667])**: the repo's session-conflicts script
|
||||
(`<session-conflicts-cmd> <ticket>`) scans sources 1-3 in one read-only pass
|
||||
(exit 4 = conflict, matching the claim script; source 1 fail-opens visibly
|
||||
when the app API is down — the backend hard guard [org-internal #1989]
|
||||
when the app API is down — the backend hard guard [TT-1989]
|
||||
backstops); source 4 IS the claim script's compare-and-swap. Dead-claim
|
||||
takeover is mechanized in the claim script (see below); manual recipes:
|
||||
the headless-session-ops skill's ticket-recipe reference §0.
|
||||
|
||||
**Dead-claim takeover ([org-internal #3668]).** A claim whose session is
|
||||
**Dead-claim takeover ([TT-3668]).** A claim whose session is
|
||||
gone (404 on the app API) and whose branch was never pushed is a DEAD claim
|
||||
— the [org-internal #3419] shape. Do NOT hand-edit the dead claim comment
|
||||
— the [TT-3419] shape. Do NOT hand-edit the dead claim comment
|
||||
(the retired admin workaround — unauditable); run the claim script's
|
||||
takeover subcommand (`<claim-takeover-cmd> <ticket> <branch> --session-id
|
||||
<id>`) instead. Evidence rule (the claim script's header is normative): a
|
||||
@@ -77,8 +76,7 @@ ticket-driven work is to claim the ticket — one atomic action of THREE
|
||||
steps, valid ONLY when all complete: (1) set the issue assignee to the
|
||||
working account, (2) post a claim comment naming the workflow branch and
|
||||
session id, (3) push the workflow branch to remote (even an empty commit —
|
||||
a purely local branch is invisible to other sessions, [org-internal
|
||||
[org-internal #2280]/[org-internal #2282]]). Use the repo's claim wrappers (staged-transaction claim
|
||||
a purely local branch is invisible to other sessions, [TT-2280]/[TT-2282]). Use the repo's claim wrappers (staged-transaction claim
|
||||
script; exit codes and CAS semantics in its header; non-zero = NOT claimed)
|
||||
and the provision wrapper (adds the worktree + Tier-1 runs scaffold). The
|
||||
manual 3-step is the fallback where the scripts are unavailable, same
|
||||
@@ -88,7 +86,7 @@ re-verification.
|
||||
branch's recent commits for `#<ticket>` — surfacing an equivalent
|
||||
implementation already on main *before* the merge rejection.
|
||||
|
||||
**Merge-time review gate ([org-internal #2345]).** `pipeline/review-code` is
|
||||
**Merge-time review gate ([TT-2345]).** `pipeline/review-code` is
|
||||
a required status: merge needs it green OR the route-based exemption
|
||||
(Kind/* close routes skip review-code — posted by the repo's
|
||||
review-gate-exemption script). Read the commit-status endpoint for the PR
|
||||
@@ -102,7 +100,7 @@ your chunk before starting.
|
||||
|
||||
Two sessions owning the same issue or code area is never faster — it is the
|
||||
exact collision this rule prevents. If a collision HAS happened, follow the
|
||||
failure-path playbook at the ownership-collision runbook (Tier-2 reference
|
||||
failure-path playbook at the ownership-collision runbook (instance detail page
|
||||
page, reachable via the ticket backend).
|
||||
|
||||
### Scope
|
||||
|
||||
@@ -13,8 +13,8 @@ each other's entries and one session's `pop` returns the other session's
|
||||
content — or `drop`/`clear` wipes uncommitted work belonging to a session in
|
||||
a different worktree.
|
||||
|
||||
This failure mode has already destroyed completed work in production ([org-internal #1655] /
|
||||
[org-internal #1629] — a finished 25-test implementation overwritten on the shared stack).
|
||||
This failure mode has already destroyed completed work in production ([TT-1655] /
|
||||
[TT-1629] — a finished 25-test implementation overwritten on the shared stack).
|
||||
|
||||
**Iron Law: NEVER use `git stash` (or `git stash pop` / `push` / `drop` /
|
||||
`clear` / `apply`) inside an octopus worktree.**
|
||||
@@ -70,7 +70,7 @@ If you must `git checkout <base>` to reproduce a failure but the worktree is
|
||||
dirty, do **not** reach for stash. Instead:
|
||||
|
||||
- WIP-commit first (option 1), or
|
||||
- Use the lifecycle-managed scratch-worktree script ([org-internal #2790]) to materialise
|
||||
- Use the lifecycle-managed scratch-worktree script ([TT-2790]) to materialise
|
||||
the base commit in a *separate* worktree and run the failing test there:
|
||||
|
||||
```bash
|
||||
@@ -82,7 +82,7 @@ dirty, do **not** reach for stash. Instead:
|
||||
classification check. The script registers the worktree, symlinks
|
||||
`node_modules` from the source checkout when `bun.lock` matches, and the
|
||||
`sweep` backstop reclaims worktrees abandoned by dying sessions — bare
|
||||
`git worktree add /tmp/octopus/...` has no such recovery ([org-internal #2790]).
|
||||
`git worktree add /tmp/octopus/...` has no such recovery ([TT-2790]).
|
||||
|
||||
### Exceptions
|
||||
|
||||
@@ -110,4 +110,4 @@ dirty, do **not** reach for stash. Instead:
|
||||
If a parallel-session stash collision happens again despite this rule, treat
|
||||
it as a Sev-2 process incident: stop work, recover via
|
||||
`git fsck --unreachable` / `git log -g --walk-reflogs stash`, open a follow-up
|
||||
referencing [org-internal #1655].
|
||||
referencing [TT-1655].
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
- Test actual implementation, do not duplicate logic into tests
|
||||
- Tests cannot run from repo root (guard: `do-not-run-tests-from-root`); run from package dirs.
|
||||
- **Local pre-check: run `<test-cmd:changed>`** from the owning package after editing source. It selects only tests affected by your uncommitted + branch changes (path-mapping ∪ CodeGraph direct dependents) and runs them in a single process — seconds, machine stays responsive. Use `--print` to see the selection without running, `--all` to scan beyond the home package.
|
||||
- **Before a delivery push: `<test-cmd:changed>` green + `<typecheck-cmd>` clean** — same selector as CI's PR side (local parity, [org-internal #4425]). The full suite (`<test-cmd:parallel>`) stays with nightly / `run-full-tests` / manual pre-merge runs. 实例命令绑定见 core/adapters/TERMINOLOGY.md。
|
||||
- **Before a delivery push: `<test-cmd:changed>` green + `<typecheck-cmd>` clean** — same selector as CI's PR side (local parity, [TT-4425]). The full suite (`<test-cmd:parallel>`) stays with nightly / `run-full-tests` / manual pre-merge runs. 实例命令绑定见 core/adapters/TERMINOLOGY.md。
|
||||
- Never use the bare single-process test runner for the full suite; `<test-cmd:parallel>` shards it and process-isolates known-corrupting files. Parallelism is controlled by `TEST_SHARDS` (default 3; raise it on beefy CI runners, e.g. `TEST_SHARDS=7`).
|
||||
|
||||
### Pre-existing test failures must be filed, not silently logged
|
||||
@@ -18,7 +18,7 @@ problem" and do NOT bury it in a report body.
|
||||
|
||||
- Classify it: run the failing test on the base commit (see `verify` Phase 2.6).
|
||||
Fails there too → pre-existing (BF); passes there → regression you must fix.
|
||||
- De-duplicate BEFORE filing (retro [org-internal #2696]): search existing
|
||||
- De-duplicate BEFORE filing (retro [TT-2696]): search existing
|
||||
`baseline-failure` tickets — open AND closed — by test/file name to surface
|
||||
candidates, then match by **failure signature** (error signature + affected
|
||||
surface — one root-cause family may span several tests; see the
|
||||
@@ -40,7 +40,7 @@ it is a **flaky test**. Do NOT silently re-run until it passes and move on.
|
||||
|
||||
- Detect: re-run the suite (or use the project's flaky detector). Record every
|
||||
test that shows intermittent behavior — name, failure rate, and run count.
|
||||
- De-duplicate BEFORE filing (retro [org-internal #2696]): same
|
||||
- De-duplicate BEFORE filing (retro [TT-2696]): same
|
||||
signature-based procedure as baseline failures above, against existing
|
||||
`flaky-test` tickets.
|
||||
- File it: the Verifier registers every un-tracked flaky test as a
|
||||
@@ -55,7 +55,7 @@ it is a **flaky test**. Do NOT silently re-run until it passes and move on.
|
||||
NOT fix it in place — classify, file, and return to your task per the
|
||||
session-scope-guard rule. A repository-wide flaky test is a shared magnet —
|
||||
fixing it in place drifts off-task and collides with its owner
|
||||
([org-internal #1803]).
|
||||
([TT-1803]).
|
||||
|
||||
### Testing Kobalte components with happydom
|
||||
|
||||
@@ -74,7 +74,7 @@ render reliably.
|
||||
|
||||
A single component MUST NOT carry both a `.test.ts` and a `.test.tsx` test
|
||||
file — the two-file split duplicated ~3300 lines of overlapping assertions
|
||||
across one UI package [org-internal #1712]. Use exactly one file per
|
||||
across one UI package [TT-1712]. Use exactly one file per
|
||||
component, chosen by test style:
|
||||
|
||||
| Test style | Extension | When to use |
|
||||
@@ -129,17 +129,17 @@ expect(source).not.toContain(`@${NAMESPACE}`)
|
||||
Each package MUST have exactly ONE test root — no parallel tracks
|
||||
(`src/**/__tests__/`, a `tests/` dir alongside colocated `src/`, or a `test/`
|
||||
alongside `tests/`); a second root drifts and breaks test discovery
|
||||
([org-internal #1711], extended to all packages by [org-internal #1821]).
|
||||
([TT-1711], extended to all packages by [TT-1821]).
|
||||
|
||||
Rules:
|
||||
|
||||
- New tests: create them at the package's single root from the start.
|
||||
- Do NOT create `src/**/__tests__/` directories in any package — parallel
|
||||
tracks drift (residuals eliminated by [org-internal #1821]).
|
||||
tracks drift (residuals eliminated by [TT-1821]).
|
||||
- For `test/`-root packages: mirror the `src/` path (`test/<src-relative>.test.ts`);
|
||||
type-level tests live alongside the behavioral suites in the config area.
|
||||
- For colocated-root packages: keep tests next to the source file; one test
|
||||
file per component [org-internal #1712].
|
||||
file per component [TT-1712].
|
||||
|
||||
Per-package root tables live in the instance layer (they name concrete
|
||||
package paths); the invariant itself — ONE root per package — is universal.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
> Core 中立版(Increment 2 改写)。术语对照见 core/adapters/TERMINOLOGY.md;本组织实例表述见 dogfood 对应文件。
|
||||
|
||||
## Ticket Lifecycle — registry-first filing, claim-to-promote ([org-internal #3002] G1)
|
||||
## Ticket Lifecycle — registry-first filing, claim-to-promote ([TT-3002] G1)
|
||||
|
||||
Bugs worth fixing start life as a **registry row**, not an independent ticket.
|
||||
This extends the two-tier-artifacts philosophy to the ticket queue: a
|
||||
@@ -25,20 +25,20 @@ is how the 2026-08 backlog formed.)
|
||||
```
|
||||
|
||||
- **TD-NNN** is allocated at REGISTRATION via the ledger mutex
|
||||
[org-internal #3322]: the 配额账本脚本 (`td-alloc` 形态, `bash <alloc-script>
|
||||
[TT-3322]: the 配额账本脚本 (`td-alloc` 形态, `bash <alloc-script>
|
||||
<count> <source-slug> [--ticket N]`) takes a contiguous range from the TD
|
||||
allocation ledger (a standing tracker issue) — append-only `**td-alloc**`
|
||||
comments, earliest-comment-id wins on collision. **ANY allocation — manual
|
||||
included — must land a td-alloc comment on the ledger BEFORE the registry
|
||||
row is written** (script, tool API, or web UI). Hand-computed `max + 1`
|
||||
without a ledger comment is FORBIDDEN (parallel-session races,
|
||||
[org-internal #3322]). The id is **reserved for life**: promotion reuses
|
||||
[TT-3322]). The id is **reserved for life**: promotion reuses
|
||||
it, never renumbers. Run the alloc script's `--check` (reconciliation)
|
||||
when the last check predates this batch, and in retrospectives.
|
||||
- **De-duplication** queries the TD index (same-source rows) plus open
|
||||
promoted issues (cross-source); index matching replaces title-keyword
|
||||
matching (keyword dedup once produced 18 fragments from one source).
|
||||
- **Query-failure ruling ([org-internal #3383]: fail-open, visible)**: if the
|
||||
- **Query-failure ruling ([TT-3383]: fail-open, visible)**: if the
|
||||
dedup query itself errors (backend API failure — NOT "queried and found no
|
||||
match"), retry once; on second failure file anyway, marking the comment
|
||||
`dedup-unverified` for retro/reconciliation sweep. Fail-closed rejected:
|
||||
@@ -63,7 +63,7 @@ source.
|
||||
### PR 准入(pr-admission,TD-678)
|
||||
|
||||
会话交付物 = 分支 + 报告;开 PR 属编排职权,按容量串行一次一张、双绿并入
|
||||
再开下一张([org-internal #3864] 管合并出口、本节管 PR 入口)。交付推送前置
|
||||
再开下一张([TT-3864] 管合并出口、本节管 PR 入口)。交付推送前置
|
||||
本地验证(`<test-cmd:changed>` + `<typecheck-cmd>` 绿;实例命令绑定见
|
||||
core/adapters/TERMINOLOGY.md)。编排不可达可自开,PR 正文标
|
||||
`uncoordinated`。细则与门控项:pipeline-gate 清单 PR 准入节。
|
||||
@@ -75,7 +75,7 @@ occurrence: evidence (run, commit, failing output, failure rate) attaches as
|
||||
comments on the family's **umbrella ticket** (ticket-backend issue), keyed by
|
||||
failure signature (error signature + affected surface, not just
|
||||
`file::test-name` — one root-cause family may span several tests; precedents
|
||||
[org-internal #2585], [org-internal #2925]). Filing a new ticket when the
|
||||
[TT-2585], [TT-2925]). Filing a new ticket when the
|
||||
signature already matches an existing family (open or closed) is forbidden —
|
||||
attach evidence instead. A family umbrella is closed when its signature no
|
||||
longer reproduces.
|
||||
|
||||
@@ -53,8 +53,7 @@ Tier 1 is an optimization an artifact opts INTO, not out of.
|
||||
### Common classifications
|
||||
|
||||
Per-artifact table (review findings, prompt files, working drafts, draft/frozen
|
||||
contracts, issue checklist, 工件索引, `index.json` …): Tier-2 reference page
|
||||
`rules/two-tier-artifacts-detail` (reachable via the ticket backend); the
|
||||
contracts, issue checklist, 工件索引, `index.json` …): instance detail page `rules/two-tier-artifacts-detail` (reachable via the ticket backend); the
|
||||
decision rule above classifies anything unlisted.
|
||||
|
||||
### Two indexes, parallel not replacement
|
||||
@@ -74,14 +73,13 @@ Closed by the **Verifier** at verify PASS (or the Orchestrator when no
|
||||
verify). The archive step is the ONLY point active-run Tier 1 content enters
|
||||
git history:
|
||||
|
||||
1. Generate the bundle [org-internal #3604]:
|
||||
1. Generate the bundle [TT-3604]:
|
||||
the run-bundle generator script with `--slug {slug} [--ticket N] [--pr N]`
|
||||
— flips meta to "archived", hashes the workspace into the `sha256_16`
|
||||
manifest, writes `archive/{ticket}-{slug}.json`, validates.
|
||||
2. Commit the bundle on the workflow branch (rides into main via `--no-ff`).
|
||||
Direct pushes to main stay blocked by branch protection [org-internal
|
||||
[org-internal #3604]]; do not bypass.
|
||||
3. **归档前置校验** [org-internal #2727]: the generator validates by default
|
||||
Direct pushes to main stay blocked by branch protection [TT-3604]; do not bypass.
|
||||
3. **归档前置校验** [TT-2727]: the generator validates by default
|
||||
(`--no-validate` must not reach a merge); red exit = fix before close.
|
||||
The L0 merge gate rejects non-compliant bundles at merge anyway.
|
||||
|
||||
@@ -109,7 +107,7 @@ reproducibility trace — enough to reconstruct what a run produced.
|
||||
the designated re-read entry — after `compact`, read `runs/{slug}/index.json`,
|
||||
not conversation memory.
|
||||
|
||||
### Gate furlough([org-internal #3607])
|
||||
### Gate furlough([TT-3607])
|
||||
|
||||
强制门的唯一退出通道是 gate 台账(furlough ledger)的 furlough 条目
|
||||
(测量证据 + reopen 条件);无台账条目的减门/跳过改动一律拒绝,台账
|
||||
|
||||
@@ -24,7 +24,7 @@ On every substantive request that is tied to a ticket, run Step 0:
|
||||
`Kind/*` label when known; omit `kind` when not yet read (the tool returns
|
||||
the default route plus a read-ticket-then-re-invoke instruction). Agents
|
||||
with the route-gate option enabled enforce this mechanically
|
||||
[org-internal #3328]: other tool calls are dispatch-rejected until the
|
||||
[TT-3328]: other tool calls are dispatch-rejected until the
|
||||
路由解析工具 runs. Do not hand-read the routing table when the tool is
|
||||
available.
|
||||
3. **Read the ticket's `Kind/*` label** from the issue body or via the issue
|
||||
@@ -38,7 +38,7 @@ On every substantive request that is tied to a ticket, run Step 0:
|
||||
`skip` / `keep_gates` downstream. Never drop a gate the route lists in
|
||||
`keep_gates`; never add back a stage the route lists in `skip`.
|
||||
|
||||
### Degradation — label missing, unknown, or wrong ([org-internal #1828] AC)
|
||||
### Degradation — label missing, unknown, or wrong ([TT-1828] AC)
|
||||
|
||||
- **No ticket / no `Kind/*` label / label not in the table** → `default`
|
||||
route (natural-language matching). State this in one line ("no Kind/\*
|
||||
@@ -64,15 +64,14 @@ On every substantive request that is tied to a ticket, run Step 0:
|
||||
|
||||
### Runtime growth signals (post-sizing)
|
||||
|
||||
Two live growth mechanisms (narrative: Tier-2 reference page
|
||||
`rules/workflow-routing-detail`, reachable via the ticket backend; retired
|
||||
Two live growth mechanisms (narrative: instance detail page `rules/workflow-routing-detail`, reachable via the ticket backend; retired
|
||||
Size/* history: the instance rules-history archive). Canonical key:
|
||||
`dag.size_derivation.oversize_signals` (TD/DUP-F009).
|
||||
|
||||
- **DAG-routed tickets** (DAG Epic, DAG-routed `Kind/Feature`, their
|
||||
`Kind/Task` children — no `Size/*` tier): runtime growth fires the
|
||||
oversize signals → response is **re-derivation + review-dag re-run**.
|
||||
- **Bug tickets (big-bug relabel rule, [org-internal #3061])**: a `Kind/Bug`
|
||||
- **Bug tickets (big-bug relabel rule, [TT-3061])**: a `Kind/Bug`
|
||||
hitting a design-level trigger (design-decision root cause, shared-contract /
|
||||
public-API change, data migration) has outgrown the bug type — mandatory
|
||||
action is **relabel `Kind/Feature`** (Step 0 reroutes into the DAG
|
||||
@@ -87,10 +86,10 @@ never quietly override.
|
||||
|
||||
The DAG ticket pipeline (`analyze-dag` → task DAG → single gate `review-dag`)
|
||||
is the **default** route for `Kind/Epic` and `Kind/Feature`
|
||||
([org-internal #3061] Phase 2 / TD-388). Both resolve via the routes table
|
||||
([TT-3061] Phase 2 / TD-388). Both resolve via the routes table
|
||||
directly — **no trigger/marker check** (route rollback = revert PR).
|
||||
Authoritative definition: the `dag:` block in the workflow-routing table;
|
||||
narrative + history: Tier-2 reference page `rules/workflow-routing-detail`.
|
||||
narrative + history: instance detail page `rules/workflow-routing-detail`.
|
||||
|
||||
1. **`Kind/Epic` or `Kind/Feature` → `dag.route`**: entry `analyze-dag`,
|
||||
single gate `review-dag` (replaces review-design-space +
|
||||
@@ -126,12 +125,12 @@ rules archive; rulings in the phase-3 retirement ruling doc (Tier-2
|
||||
reference, reachable via the ticket backend). Nothing trims gates —
|
||||
`never_trim` is structural.
|
||||
|
||||
### 立案降档 — filing/sprint-mode([org-internal #3002] G5 / [org-internal #3007])
|
||||
### 立案降档 — filing/sprint-mode([TT-3002] G5 / [TT-3007])
|
||||
|
||||
Sprint 期间债务侧显式降档,不靠纪律。开关:routing table `filing.sprint-mode`
|
||||
(默认 `false`)。`true`(冲刺期)时 verify Phase 5.5 registry-only 不分严重度
|
||||
(登记行照写、零丢失;独立工单创建冻结至开关回 `false`,已登记行按
|
||||
ticket-lifecycle 规则正常认领升票;期间 HIGH/MEDIUM 行不被 reaper 触碰,
|
||||
[org-internal #3004])。BF/FT(5.55/5.56)不受影响。谁翻转:冲刺负责人(人),
|
||||
[TT-3004])。BF/FT(5.55/5.56)不受影响。谁翻转:冲刺负责人(人),
|
||||
在冲刺跟踪单记一行;开关值即 routing table 当前值,verify 每次运行时读取。
|
||||
动机与细节:Tier-2 参考页(经 ticket backend)`rules/workflow-routing-detail`。
|
||||
动机与细节:instance detail page `rules/workflow-routing-detail`。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"namespace": "https://eightarms.net/octopus-workflow/schemas/",
|
||||
"frozen": false,
|
||||
"note": "发布仓创建时置 frozen: true——$id 一经发布不可变(v3 §G);别名保留 ≥2 个 major 版本",
|
||||
"frozen": true,
|
||||
"note": "已置 frozen: true(live 迁移完成,2026-09)——$id 一经发布不可变(v3 §G);别名保留 ≥2 个 major 版本",
|
||||
"aliases": [
|
||||
{
|
||||
"old": "https://eightarms.net/fourbroad/octopus/.octopus/schemas/port-analysis.schema.json",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://eightarms.net/octopus-workflow/schemas/port-analysis.schema.json",
|
||||
"title": "Port Analysis Reviewer Output",
|
||||
"description": "Schema for per-dimension port-analysis reviewer findings. Used by the large-port-pipeline source analysis review (Phase B1.5). The port source-analysis pipeline uses a deliberate three-value severity contract 鈥?BLOCKER / MAJOR / MINOR 鈥?and never emits INFO (matching implement/reference/large-port-pipeline.md and source-analysis.md, which name only those three). This is a documented exception to the canonical four-value set (BLOCKER / MAJOR / MINOR / INFO) in reviewer-output.schema.json and synthesis.schema.json.",
|
||||
"description": "Schema for per-dimension port-analysis reviewer findings. Used by the large-port-pipeline source analysis review (Phase B1.5). The port source-analysis pipeline uses a deliberate three-value severity contract — BLOCKER / MAJOR / MINOR — and never emits INFO (matching implement/reference/large-port-pipeline.md and source-analysis.md, which name only those three). This is a documented exception to the canonical four-value set (BLOCKER / MAJOR / MINOR / INFO) in reviewer-output.schema.json and synthesis.schema.json.",
|
||||
"type": "object",
|
||||
"required": ["dimension", "findings"],
|
||||
"properties": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://eightarms.net/octopus-workflow/schemas/review-status.schema.json",
|
||||
"title": "Review Status",
|
||||
"description": "Schema for tracking the lifecycle state of a review session. This file lives at runs/{slug}/reviews/{stage}/status.json: initialized by the Orchestrator at Phase A (step 0.5) with the full required set, appended by the Synthesizer at Phase B (history[] + current_round), and finalized with `converged` by the Orchestrator at Phase E (see skills/_shared/review-pipeline-phases.md). Reader: the retrospective token-telemetry probe (retrospective/scripts/token-telemetry.ts) walks runs/**/reviews/*/status.json (canonical) and the legacy .artifacts/**/reviews/*/status.json, reading `history[]` (code-level legacy alias `rounds[]`, both handled) and `current_round`. For CLOSED runs (active workspace removed at archive-at-close), the probe reconstructs per-stage round counts from reviews/{stage}/round{N}/ artifact paths in the committed archive bundle runs/archive/{slug}.json ([org-internal #2591]). Since TD/TRC-F006 ([org-internal #2688]) the archive bundle can also embed an explicit digest of this history[] (top-level review_history: {stage, rounds, final_verdict, per_round[]}) so round counts and verdicts stay verifiable offline, without path reconstruction.",
|
||||
"description": "Schema for tracking the lifecycle state of a review session. This file lives at runs/{slug}/reviews/{stage}/status.json: initialized by the Orchestrator at Phase A (step 0.5) with the full required set, appended by the Synthesizer at Phase B (history[] + current_round), and finalized with `converged` by the Orchestrator at Phase E (see skills/_shared/review-pipeline-phases.md). Reader: the retrospective token-telemetry probe (retrospective/scripts/token-telemetry.ts) walks runs/**/reviews/*/status.json (canonical) and the legacy .artifacts/**/reviews/*/status.json, reading `history[]` (code-level legacy alias `rounds[]`, both handled) and `current_round`. For CLOSED runs (active workspace removed at archive-at-close), the probe reconstructs per-stage round counts from reviews/{stage}/round{N}/ artifact paths in the committed archive bundle runs/archive/{slug}.json ([TT-2591]). Since TD/TRC-F006 ([TT-2688]) the archive bundle can also embed an explicit digest of this history[] (top-level review_history: {stage, rounds, final_verdict, per_round[]}) so round counts and verdicts stay verifiable offline, without path reconstruction.",
|
||||
"type": "object",
|
||||
"required": ["slug", "started_at", "current_round", "max_rounds", "converged", "history"],
|
||||
"properties": {
|
||||
@@ -19,7 +19,7 @@
|
||||
"max_rounds": {
|
||||
"type": "integer",
|
||||
"default": 3,
|
||||
"description": "Per-skill bound: `review-artifact` skill (process target) = 3 (the roadmap/design/plan targets were archived 2026-08-21, [org-internal #3072] phase 3); `review-code` = 2 default / 3 high-risk (`workflow-routing.yaml` `review.max_rounds`, [org-internal #3567]). `review-dag` (the review-artifact skill's DAG single-gate target) binds per depth from `dag_metrics.review_depth`: D1 鈮?, D2 鈮?, D3 鈮?, D4 鈮? 鈥?D4 reaches round 4, exceeding the shared `review-artifact` default, so the DAG per-depth cap takes precedence (see review-artifact/SKILL.md review-dag Phase D MAX_ROUNDS). Set explicitly by the skill; default 3 is a fallback only."
|
||||
"description": "Per-skill bound: `review-artifact` skill (process target) = 3 (the roadmap/design/plan targets were archived 2026-08-21, [TT-3072] phase 3); `review-code` = 2 default / 3 high-risk (`workflow-routing.yaml` `review.max_rounds`, [TT-3567]). `review-dag` (the review-artifact skill's DAG single-gate target) binds per depth from `dag_metrics.review_depth`: D1 ≤2, D2 ≤3, D3 ≤3, D4 ≤4 — D4 reaches round 4, exceeding the shared `review-artifact` default, so the DAG per-depth cap takes precedence (see review-artifact/SKILL.md review-dag Phase D MAX_ROUNDS). Set explicitly by the skill; default 3 is a fallback only."
|
||||
},
|
||||
"converged": {
|
||||
"type": "boolean"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://eightarms.net/octopus-workflow/schemas/reviewer-output.schema.json",
|
||||
"title": "Reviewer Output",
|
||||
"description": "Schema for a single reviewer's output for one review dimension. Also the Tier 1 review-findings schema ([org-internal #1988]): migrated skills (review-code) write each dimension's finding as a JSON file at runs/{slug}/reviews/{stage}/round{N}/findings-{DIMENSION_CODE}.json validated by this schema; the index.json row for that file carries type=review-findings, schema=this $id. When a dimension has multiple reviewers (dim_split > 1, e.g. D3 TOPO:2 / D4 TOPO:2), each writes its OWN slot file findings-{DIMENSION_CODE}-r{k}.json with reviewer_slot/reviewer_count set. See templates/runs-layout.md and rules/two-tier-artifacts.md.",
|
||||
"description": "Schema for a single reviewer's output for one review dimension. Also the Tier 1 review-findings schema ([TT-1988]): migrated skills (review-code) write each dimension's finding as a JSON file at runs/{slug}/reviews/{stage}/round{N}/findings-{DIMENSION_CODE}.json validated by this schema; the index.json row for that file carries type=review-findings, schema=this $id. When a dimension has multiple reviewers (dim_split > 1, e.g. D3 TOPO:2 / D4 TOPO:2), each writes its OWN slot file findings-{DIMENSION_CODE}-r{k}.json with reviewer_slot/reviewer_count set. See templates/runs-layout.md and rules/two-tier-artifacts.md.",
|
||||
"type": "object",
|
||||
"required": ["dimension", "dimension_label", "verdict", "quantitative_summary", "findings", "reviewed_files"],
|
||||
"properties": {
|
||||
@@ -17,7 +17,7 @@
|
||||
"reviewer_slot": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"description": "1-based slot of this reviewer WITHIN its dimension, when dim_split assigns >1 reviewer to the dimension (e.g. review-dag D3 TOPO:2, D4 TOPO:2 鈥?dim_split per `workflow-routing.yaml` dag.size_derivation.review_depth). Multi-reviewer dimensions write one file per slot: findings-{DIMENSION_CODE}-r{k}.json. Omitted for single-reviewer dimensions (file stays findings-{DIMENSION_CODE}.json). Preserves per-reviewer attribution for the retrospective overlap analysis ([org-internal #2996] step 1a)."
|
||||
"description": "1-based slot of this reviewer WITHIN its dimension, when dim_split assigns >1 reviewer to the dimension (e.g. review-dag D3 TOPO:2, D4 TOPO:2 — dim_split per `workflow-routing.yaml` dag.size_derivation.review_depth). Multi-reviewer dimensions write one file per slot: findings-{DIMENSION_CODE}-r{k}.json. Omitted for single-reviewer dimensions (file stays findings-{DIMENSION_CODE}.json). Preserves per-reviewer attribution for the retrospective overlap analysis ([TT-2996] step 1a)."
|
||||
},
|
||||
"reviewer_count": {
|
||||
"type": "integer",
|
||||
@@ -79,7 +79,7 @@
|
||||
"checklist_ref": {
|
||||
"type": "string",
|
||||
"pattern": "^[A-Z0-9]{2,6} \\d+(\\.\\d+)+(\\s*\\([^\\)]*\\))?(\\s*/\\s*[A-Z0-9]{2,6} \\d+(\\.\\d+)+(\\s*\\([^\\)]*\\))?)*$",
|
||||
"description": "Checklist item reference, e.g. COR 1.1, INV 1.3, SEC 3.7.1, STD 8.4 鈥?dimension/section code followed by item number(s)."
|
||||
"description": "Checklist item reference, e.g. COR 1.1, INV 1.3, SEC 3.7.1, STD 8.4 — dimension/section code followed by item number(s)."
|
||||
},
|
||||
"location": {
|
||||
"type": "string",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://eightarms.net/octopus-workflow/schemas/runs-bundle.schema.json",
|
||||
"title": "Tier 1 Run Archive Bundle",
|
||||
"description": "Composite archive bundle committed at close: runs/archive/{slug}.json = {meta, index}. Dual-profile by schema_version: >= 2 strict (closed core field set + free-form context bag), 1 or absent legacy (structural typing only; historical drift normalized by repair-run-bundles.ts, see [org-internal #2588]). Validated by validate-run-bundles.ts; CI wiring: .gitea/workflows/octopus-schemas.yml. Authoritative layout: templates/runs-layout.md. Boundary rule: rules/two-tier-artifacts.md.",
|
||||
"description": "Composite archive bundle committed at close: runs/archive/{slug}.json = {meta, index}. Dual-profile by schema_version: >= 2 strict (closed core field set + free-form context bag), 1 or absent legacy (structural typing only; historical drift normalized by repair-run-bundles.ts, see [TT-2588]). Validated by validate-run-bundles.ts; CI wiring: .gitea/workflows/octopus-schemas.yml. Authoritative layout: templates/runs-layout.md. Boundary rule: rules/two-tier-artifacts.md.",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["meta", "index"],
|
||||
@@ -11,11 +11,11 @@
|
||||
"index": true,
|
||||
"working_notes": {
|
||||
"type": "string",
|
||||
"description": "Final content of runs/{slug}/working-notes.md ([org-internal #2600]), inlined at archive time when the file exists. The one Tier 1 artifact whose CONTENT (not just digest) rides in the bundle 鈥?the run's narrative memory (decisions, dead ends, reviewer feedback), consumed by later retro probes and the notes-injection degradation path ([org-internal #2601]). Absent when the run kept no working notes."
|
||||
"description": "Final content of runs/{slug}/working-notes.md ([TT-2600]), inlined at archive time when the file exists. The one Tier 1 artifact whose CONTENT (not just digest) rides in the bundle — the run's narrative memory (decisions, dead ends, reviewer feedback), consumed by later retro probes and the notes-injection degradation path ([TT-2601]). Absent when the run kept no working notes."
|
||||
},
|
||||
"review_history": {
|
||||
"type": "array",
|
||||
"description": "Offline-verifiability digest of the run's review rounds (TD/TRC-F006, [org-internal #2688]): one entry per review stage the run executed, each derived from that stage's live reviews/{stage}/status.json history[] at archive time. Lets closed-run probes reconstruct round counts and verdicts from the bundle alone, without the (removed) live workspace or path reconstruction ([org-internal #2591]). Absent when the run kept no review rounds.",
|
||||
"description": "Offline-verifiability digest of the run's review rounds (TD/TRC-F006, [TT-2688]): one entry per review stage the run executed, each derived from that stage's live reviews/{stage}/status.json history[] at archive time. Lets closed-run probes reconstruct round counts and verdicts from the bundle alone, without the (removed) live workspace or path reconstruction ([TT-2591]). Absent when the run kept no review rounds.",
|
||||
"items": { "$ref": "#/$defs/reviewHistoryEntry" }
|
||||
}
|
||||
},
|
||||
@@ -55,7 +55,7 @@
|
||||
"stage": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Review stage identifier matching the reviews/{stage}/ directory (e.g. code, review-dag, audit-process 鈥?the live values; design-space is a retired historical value)."
|
||||
"description": "Review stage identifier matching the reviews/{stage}/ directory (e.g. code, review-dag, audit-process — the live values; design-space is a retired historical value)."
|
||||
},
|
||||
"rounds": { "type": "integer", "minimum": 1, "description": "Number of executed rounds." },
|
||||
"final_verdict": { "type": "string", "enum": ["PASS", "WARN", "FAIL"] },
|
||||
@@ -109,7 +109,7 @@
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"required": ["slug", "state", "created_at"],
|
||||
"description": "Legacy profile (schema_version 1 or absent): historical bundles AND current live-workspace runs 鈥?runs-meta.schema.json / runs-index.schema.json pin schema_version 1 today. Core fields type-checked when present; extra context properties (route/pr/node/kind/...) tolerated as-is. The v2 strict profile (below) is the migration target: it becomes the profile for new runs once the live-workspace schemas are bumped to emit schema_version 2 with the context bag.",
|
||||
"description": "Legacy profile (schema_version 1 or absent): historical bundles AND current live-workspace runs — runs-meta.schema.json / runs-index.schema.json pin schema_version 1 today. Core fields type-checked when present; extra context properties (route/pr/node/kind/...) tolerated as-is. The v2 strict profile (below) is the migration target: it becomes the profile for new runs once the live-workspace schemas are bumped to emit schema_version 2 with the context bag.",
|
||||
"properties": {
|
||||
"schema_version": { "type": "integer", "minimum": 1 },
|
||||
"slug": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
|
||||
@@ -132,7 +132,7 @@
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["schema_version", "slug", "state", "created_at", "updated_at", "ticket"],
|
||||
"description": "Strict profile (schema_version 2): closed core field set. Run-specific context (route/pr/node/task_node/...) goes in the context bag 鈥?the ONLY place for non-core fields.",
|
||||
"description": "Strict profile (schema_version 2): closed core field set. Run-specific context (route/pr/node/task_node/...) goes in the context bag — the ONLY place for non-core fields.",
|
||||
"allOf": [
|
||||
{
|
||||
"if": { "properties": { "state": { "const": "archived" } }, "required": ["state"] },
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://eightarms.net/octopus-workflow/schemas/runs-index.schema.json",
|
||||
"title": "Tier 1 Run Artifact Index",
|
||||
"description": "Schema for runs/{slug}/index.json 鈥?the artifact manifest for a Tier 1 local structured run. This is the compact-recovery entry point after compaction (compact never deletes local files). Parallel to, not a replacement for, the Tier 2 '## 宸ヤ欢绱㈠紩' issue comment. Authoritative layout: templates/runs-layout.md. Boundary rule: rules/two-tier-artifacts.md.",
|
||||
"description": "Schema for runs/{slug}/index.json — the artifact manifest for a Tier 1 local structured run. This is the compact-recovery entry point after compaction (compact never deletes local files). Parallel to, not a replacement for, the Tier 2 '## 工件索引' issue comment. Authoritative layout: templates/runs-layout.md. Boundary rule: rules/two-tier-artifacts.md.",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["schema_version", "slug", "artifacts"],
|
||||
@@ -24,7 +24,7 @@
|
||||
"artifacts": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/$defs/artifact" },
|
||||
"description": "One entry per Tier 1 artifact in this run. Tier 2 artifacts (Gitea issue comments, wiki pages, commit status, PRs) are NEVER listed here 鈥?this index is Tier 1 only."
|
||||
"description": "One entry per Tier 1 artifact in this run. Tier 2 artifacts (Gitea issue comments, wiki pages, commit status, PRs) are NEVER listed here — this index is Tier 1 only."
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
@@ -55,7 +55,7 @@
|
||||
"browser-evidence",
|
||||
"other"
|
||||
],
|
||||
"description": "Artifact category. 'meta'/'index' for the manifest files themselves; stage categories for produced artifacts. 'review-synthesis' marks a synthesis result artifact (round verdict) as distinct from 'synthesis-prompt' (the Phase B task prompt) and 'review-status' (the lifecycle file). 'precondition-gate' marks the review-code mechanical-green gate log. 'working-notes' is the cross-stage narrative memory file ([org-internal #2600]) 鈥?one file per run, appended by every role at close, registered once (stage/produced_by null: multi-stage, multi-role). 'browser-evidence' marks a browser evidence pack manifest ([org-internal #4497] N-03, browser/{session-id}/manifest.json 鈥?shared/pack-manifest-v1)."
|
||||
"description": "Artifact category. 'meta'/'index' for the manifest files themselves; stage categories for produced artifacts. 'review-synthesis' marks a synthesis result artifact (round verdict) as distinct from 'synthesis-prompt' (the Phase B task prompt) and 'review-status' (the lifecycle file). 'precondition-gate' marks the review-code mechanical-green gate log. 'working-notes' is the cross-stage narrative memory file ([TT-2600]) — one file per run, appended by every role at close, registered once (stage/produced_by null: multi-stage, multi-role). 'browser-evidence' marks a browser evidence pack manifest ([TT-4497] N-03, browser/{session-id}/manifest.json — shared/pack-manifest-v1)."
|
||||
},
|
||||
"schema": {
|
||||
"type": ["string", "null"],
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://eightarms.net/octopus-workflow/schemas/runs-meta.schema.json",
|
||||
"title": "Tier 1 Run Metadata",
|
||||
"description": "Schema for runs/{slug}/meta.json 鈥?run metadata for a Tier 1 local structured run. Authoritative layout: templates/runs-layout.md. Boundary rule: rules/two-tier-artifacts.md. State transitions active -> archived at close (archive-at-close).",
|
||||
"description": "Schema for runs/{slug}/meta.json — run metadata for a Tier 1 local structured run. Authoritative layout: templates/runs-layout.md. Boundary rule: rules/two-tier-artifacts.md. State transitions active -> archived at close (archive-at-close).",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
@@ -89,12 +89,12 @@
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "RFC 3339 timestamp 鈥?run creation."
|
||||
"description": "RFC 3339 timestamp — run creation."
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "RFC 3339 timestamp 鈥?last metadata mutation."
|
||||
"description": "RFC 3339 timestamp — last metadata mutation."
|
||||
},
|
||||
"closed_at": {
|
||||
"type": ["string", "null"],
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://eightarms.net/octopus-workflow/schemas/workflow-routing.schema.json",
|
||||
"title": "Workflow Routing Table",
|
||||
"description": "Schema for workflow-routing.yaml 鈥?type-driven (Kind/*) process selection. Referenced by rules/workflow-routing.md and the auto-approve rule. When this schema and the rules markdown disagree, the YAML (validated by this schema) is authoritative.",
|
||||
"description": "Schema for workflow-routing.yaml — type-driven (Kind/*) process selection. Referenced by rules/workflow-routing.md and the auto-approve rule. When this schema and the rules markdown disagree, the YAML (validated by this schema) is authoritative.",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["version", "default", "routes"],
|
||||
@@ -23,7 +23,7 @@
|
||||
"$defs": {
|
||||
"stage": {
|
||||
"type": "string",
|
||||
"description": "A pipeline stage identifier 鈥?the 5 live gates (post-[org-internal #3072] phase 3, 2026-08-21): review-dag, review-code, verify, audit-process, merge-pr. Production-phase names (requirements, design, roadmap, implement) and the 7 retired stage ids (roadmap-exit, review-roadmap, requirements-exit, design-exit, review-design-space, review-iteration-plan, plan-iterations) are no longer valid anywhere 鈥?the sizing block that consumed the phase names was retired the same ruling.",
|
||||
"description": "A pipeline stage identifier — the 5 live gates (post-[TT-3072] phase 3, 2026-08-21): review-dag, review-code, verify, audit-process, merge-pr. Production-phase names (requirements, design, roadmap, implement) and the 7 retired stage ids (roadmap-exit, review-roadmap, requirements-exit, design-exit, review-design-space, review-iteration-plan, plan-iterations) are no longer valid anywhere — the sizing block that consumed the phase names was retired the same ruling.",
|
||||
"enum": ["review-dag", "review-code", "verify", "audit-process", "merge-pr"]
|
||||
},
|
||||
"entry": {
|
||||
@@ -33,7 +33,7 @@
|
||||
"skill": {
|
||||
"type": ["string", "null"],
|
||||
"enum": ["implement", "review-artifact", "review-code", "verify", "analyze-dag", null],
|
||||
"description": "Skill name to enter, or null for natural-language routing. The legacy roadmap / requirements-elicitation / design / plan-iterations entries were removed when those skills were archived ([org-internal #3072] phase 3, 2026-08-21 - the instance archive)."
|
||||
"description": "Skill name to enter, or null for natural-language routing. The legacy roadmap / requirements-elicitation / design / plan-iterations entries were removed when those skills were archived ([TT-3072] phase 3, 2026-08-21 - the instance archive)."
|
||||
},
|
||||
"mode": {
|
||||
"type": ["string", "null"],
|
||||
@@ -56,20 +56,20 @@
|
||||
"preflight": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/$defs/preflightItem" },
|
||||
"description": "Evidence-based producer pre-flight checklist ([org-internal #2599]) 鈥?landed by a human from retrospective PRE-FLIGHT PROPOSAL rows. Absent/empty = no injection. Cap is governed by preflight.max_items (policy), not the schema."
|
||||
"description": "Evidence-based producer pre-flight checklist ([TT-2599]) — landed by a human from retrospective PRE-FLIGHT PROPOSAL rows. Absent/empty = no injection. Cap is governed by preflight.max_items (policy), not the schema."
|
||||
},
|
||||
"notes": { "type": "string" },
|
||||
"effort": {
|
||||
"type": "string",
|
||||
"enum": ["low", "high", "max"],
|
||||
"description": "Reasoning-effort hint for this route (llm-latency phase 2): maps onto the active model's variant table when it exposes one (GLM-5.2+ low/high/max); fail-open otherwise. Reserve `low` for genuinely lightweight routes (direct-edit, no pipeline) 鈥?reasoning dominates GLM-5.3 generation latency."
|
||||
"description": "Reasoning-effort hint for this route (llm-latency phase 2): maps onto the active model's variant table when it exposes one (GLM-5.2+ low/high/max); fail-open otherwise. Reserve `low` for genuinely lightweight routes (direct-edit, no pipeline) — reasoning dominates GLM-5.3 generation latency."
|
||||
}
|
||||
}
|
||||
},
|
||||
"preflightPolicy": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Thresholds for the retro 鈫?routes.{Kind}.preflight evidence loop ([org-internal #2599]). Authoritative values live here; the retrospective consults this block, it does not restate the numbers.",
|
||||
"description": "Thresholds for the retro → routes.{Kind}.preflight evidence loop ([TT-2599]). Authoritative values live here; the retrospective consults this block, it does not restate the numbers.",
|
||||
"properties": {
|
||||
"max_items": { "type": "integer", "minimum": 1 },
|
||||
"min_sample": { "type": "integer", "minimum": 0 },
|
||||
@@ -86,7 +86,7 @@
|
||||
"item": { "type": "string", "description": "One checklist line the Producer verifies before implementing." },
|
||||
"evidence": {
|
||||
"type": "string",
|
||||
"description": "Retro reference justifying the item, e.g. 'retro [org-internal #2599]: COR 脳 unhandled-null, 5/8 first-round FAILs on Kind/Bug'."
|
||||
"description": "Retro reference justifying the item, e.g. 'retro [TT-2599]: COR × unhandled-null, 5/8 first-round FAILs on Kind/Bug'."
|
||||
},
|
||||
"added_cycle": {
|
||||
"type": "string",
|
||||
@@ -97,23 +97,23 @@
|
||||
"filing": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Filing policy (绔嬫/鐧昏绛栫暐). sprint-mode ([org-internal #3007]): when true, verify Phase 5.5 promotes registry rows to tickets in sprint mode only. work-ticket-wip-cap ([org-internal #3005] G3): open non-TD work tickets beyond this count require scheduling evidence, else they stay registry rows.",
|
||||
"description": "Filing policy (立案/登记策略). sprint-mode ([TT-3007]): when true, verify Phase 5.5 promotes registry rows to tickets in sprint mode only. work-ticket-wip-cap ([TT-3005] G3): open non-TD work tickets beyond this count require scheduling evidence, else they stay registry rows.",
|
||||
"properties": {
|
||||
"sprint-mode": {
|
||||
"type": "boolean",
|
||||
"description": "Sprint-mode filing downgrade switch ([org-internal #3007])."
|
||||
"description": "Sprint-mode filing downgrade switch ([TT-3007])."
|
||||
},
|
||||
"work-ticket-wip-cap": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "WIP cap on open non-TD work tickets (Kind/* without assignee) before new filings require scheduling evidence ([org-internal #3005] G3)."
|
||||
"description": "WIP cap on open non-TD work tickets (Kind/* without assignee) before new filings require scheduling evidence ([TT-3005] G3)."
|
||||
}
|
||||
}
|
||||
},
|
||||
"review": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Review round budget (process-diet P0b, [org-internal #3567]/TD-564): a tail cut, not the norm 鈥?at budget without convergence, STOP; residual findings flow to the TD registry. High risk = a BLOCKER survived a round or the diff touches a frozen cross-session contract.",
|
||||
"description": "Review round budget (process-diet P0b, [TT-3567]/TD-564): a tail cut, not the norm — at budget without convergence, STOP; residual findings flow to the TD registry. High risk = a BLOCKER survived a round or the diff touches a frozen cross-session contract.",
|
||||
"required": ["max_rounds"],
|
||||
"properties": {
|
||||
"max_rounds": {
|
||||
@@ -152,7 +152,7 @@
|
||||
"preflight": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/$defs/preflightItem" },
|
||||
"description": "Evidence-based pre-flight checklist for the DAG route ([org-internal #2905] 鏂规 3) 鈥?same item shape as routes.{Kind}.preflight ([org-internal #2599]). Landed by a human from retrospective PRE-FLIGHT PROPOSAL rows, including the 'REQ 脳 late-discovery' root cause (requirements found only after the DAG froze: DAG oversize signals, demo-period feedback). Consumed by analyze-dag (the route's entry skill) before decomposition. Absent/empty = no injection. Optional 鈥?deliberately NOT in dagRoute.required (spec-02 搂2.8 frozen required array unchanged). Cap governed by preflight.max_items (policy), not the schema."
|
||||
"description": "Evidence-based pre-flight checklist for the DAG route ([TT-2905] 方案 3) — same item shape as routes.{Kind}.preflight ([TT-2599]). Landed by a human from retrospective PRE-FLIGHT PROPOSAL rows, including the 'REQ × late-discovery' root cause (requirements found only after the DAG froze: DAG oversize signals, demo-period feedback). Consumed by analyze-dag (the route's entry skill) before decomposition. Absent/empty = no injection. Optional — deliberately NOT in dagRoute.required (spec-02 §2.8 frozen required array unchanged). Cap governed by preflight.max_items (policy), not the schema."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -183,7 +183,7 @@
|
||||
"replaces": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Historical documentation of which legacy gates the single gate replaced ([org-internal #3072] phase 3 retired them) 鈥?free-form strings, not the live stage vocabulary."
|
||||
"description": "Historical documentation of which legacy gates the single gate replaced ([TT-3072] phase 3 retired them) — free-form strings, not the live stage vocabulary."
|
||||
},
|
||||
"depth_from": { "type": "string", "enum": ["size_derivation"] },
|
||||
"never_trim": { "type": "boolean" }
|
||||
@@ -201,7 +201,7 @@
|
||||
"items": { "type": "string", "enum": ["Kind/Epic", "Kind/Feature"] },
|
||||
"uniqueItems": true,
|
||||
"minItems": 1,
|
||||
"description": "Ticket kinds whose DAG children reference them as ## 鐖剁骇 / Parent ([org-internal #3061] Phase 2 / TD-388: Kind/Feature added alongside Kind/Epic)."
|
||||
"description": "Ticket kinds whose DAG children reference them as ## 父级 / Parent ([TT-3061] Phase 2 / TD-388: Kind/Feature added alongside Kind/Epic)."
|
||||
},
|
||||
"parent_aggregator": { "type": "boolean" }
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
> - `frontend/SKILL.md`
|
||||
>
|
||||
> (The `roadmap`, `requirements-elicitation`, `design`, and `plan-iterations`
|
||||
> referencing skills were archived 2026-08-21, [org-internal #3072] phase 3 — see
|
||||
> referencing skills were archived 2026-08-21, [TT-3072] phase 3 — see
|
||||
> `.octopus/archive/skills/`; their copies of this directive moved with them.)
|
||||
>
|
||||
> **When editing:** update this file only. Each skill references this file via a
|
||||
|
||||
@@ -70,6 +70,6 @@
|
||||
`review-dag` (review-artifact targets — same id feeds the
|
||||
`pipeline/{REVIEW_TYPE}` commit-status context; see review-artifact Phase
|
||||
Bindings). (The design-space/plan targets were archived 2026-08-21,
|
||||
[org-internal #3072] phase 3.)
|
||||
[TT-3072] phase 3.)
|
||||
- `{DIMENSION_COUNT}` — 10 (code review; 9 in standalone-bugfix mode), 3 (review-dag single gate), or 10 (process audit); used in
|
||||
the skill's SKILL.md reference text, not inside this template body
|
||||
|
||||
@@ -113,7 +113,7 @@ Each skill references this base template via `core/skills/_shared/review-orchest
|
||||
rather than inlining the JSON array. This centralization ensures the base
|
||||
permission surface stays consistent across all review/audit skills.
|
||||
|
||||
**Tier-1 local exception** ([org-internal #1988]): migrated skills that write raw per-dimension
|
||||
**Tier-1 local exception** ([TT-1988]): migrated skills that write raw per-dimension
|
||||
findings to `<runs-root>/**` (e.g. `review-code`) add ONE scoped `edit` allow
|
||||
to the base set — `{ permission: "edit", pattern: "<runs-root>/**", action:
|
||||
"allow" }` — so the reviewer can write its OWN finding file. This is a
|
||||
@@ -122,7 +122,7 @@ edit on the code under review, so rule #7 (auditor independence) holds. See
|
||||
`_shared/review-pipeline-phases.md` Phase A step 4 and `review-code/SKILL.md`
|
||||
Phase A step 3 for the inline extended array.
|
||||
|
||||
Residual risk — accepted trade-off (TD/STD-F004, [org-internal #2688]): the grant is scoped
|
||||
Residual risk — accepted trade-off (TD/STD-F004, [TT-2688]): the grant is scoped
|
||||
to `<runs-root>/**`, wider than the reviewer's own findings file. Per-file
|
||||
narrowing was considered and rejected: findings paths are round- and
|
||||
dimension-dependent (`{slug}/reviews/{stage}/round{N}/findings-{DIMENSION_CODE}.json`),
|
||||
@@ -132,7 +132,7 @@ residual exposure — a misbehaving reviewer could overwrite a sibling stage's
|
||||
Tier 1 files — is recorded here as accepted; auditor independence is
|
||||
unaffected (code under review lives outside `runs/`).
|
||||
|
||||
### No bash for Explorer sub-agents (deliberate boundary, [org-internal #2115] RC4 / [org-internal #2126])
|
||||
### No bash for Explorer sub-agents (deliberate boundary, [TT-2115] RC4 / [TT-2126])
|
||||
|
||||
Explorer sub-agents (Reviewer / auditor / Tool roles) have **no bash**. The
|
||||
`explorer` agent is built deny-by-default at
|
||||
@@ -151,7 +151,7 @@ Synthesizer / Verifier's job (Worker sub-agents, which DO have bash via the
|
||||
`worker` agent defaults) — not the Reviewer's. Report the need in findings
|
||||
instead of attempting bash.
|
||||
|
||||
> **[org-internal #2126] Task 2 conclusion — keep + document.** The `deny **` pushed per-tool
|
||||
> **[TT-2126] Task 2 conclusion — keep + document.** The `deny **` pushed per-tool
|
||||
> at `<harness-package>/src/session/prompt.ts` is the **session tool-enable /
|
||||
> disable map** (it disables `todowrite` / `task` / `experimental.primary_tools`
|
||||
> for subagents and allows forwarded MCP tools). It is NOT the source of the
|
||||
@@ -165,4 +165,4 @@ instead of attempting bash.
|
||||
- `{REVISION_ROLE}` — "Developer" (code review), "Analyst" (review-dag single
|
||||
gate), or "Remediator" (process audit). The Worker role that revises
|
||||
artifacts between rounds. (The Architect/Planner revision roles belonged to
|
||||
the archived design-space / iteration-plan targets, [org-internal #3072] phase 3.)
|
||||
the archived design-space / iteration-plan targets, [TT-3072] phase 3.)
|
||||
|
||||
@@ -9,14 +9,14 @@ parameters and reference this doc rather than duplicating the shared mechanics.
|
||||
legitimately uses "auditor"/"Re-audit" terminology. All generic descriptions
|
||||
use `{REVIEWER_OR_AUDITOR}`.
|
||||
|
||||
**Output model — two findings sinks** ([org-internal #1988] Tier 1 migration): raw per-dimension
|
||||
**Output model — two findings sinks** ([TT-1988] Tier 1 migration): raw per-dimension
|
||||
reviewer findings have ONE of two sinks, chosen per skill. The **synthesis**
|
||||
(human gate) and **commit status** are ALWAYS Tier 2 (Gitea) regardless of the
|
||||
findings sink.
|
||||
|
||||
| Sink | Skills | Reviewer writes findings to | Synthesizer reads findings from |
|
||||
|---|---|---|---|
|
||||
| `tier1-local` (migrated) | `review-code`, `review-artifact` (live targets: review-dag, audit-process; the roadmap/design-space/plan targets were archived 2026-08-21, [org-internal #3072] phase 3) | `<runs-root>/{slug}/reviews/{stage}/round{N}/findings-{DIMENSION_CODE}.json` (validated by `core/schemas/reviewer-output.schema.json`) | the local finding files (no Gitea call) |
|
||||
| `tier1-local` (migrated) | `review-code`, `review-artifact` (live targets: review-dag, audit-process; the roadmap/design-space/plan targets were archived 2026-08-21, [TT-3072] phase 3) | `<runs-root>/{slug}/reviews/{stage}/round{N}/findings-{DIMENSION_CODE}.json` (validated by `core/schemas/reviewer-output.schema.json`) | the local finding files (no Gitea call) |
|
||||
| `tier2-comment` (fallback) | _(none — all targets migrated)_ | Gitea PR/issue comment via `工单评论 API(见 TERMINOLOGY)` (Pattern 5) | `工单评论 API(见 TERMINOLOGY)` (Pattern 3) |
|
||||
|
||||
Migration complete — every review/audit skill now outputs `tier1-local`; the
|
||||
@@ -61,19 +61,20 @@ in `_shared/gitea-write-patterns.md`.
|
||||
`stage` = `{REVIEW_TYPE}`, `produced_by` = `Orchestrator`, `schema` = the
|
||||
review-status `$id`).
|
||||
|
||||
1. **Tool-availability probe** (defense-in-depth, [org-internal #2115] RC1 / [org-internal #2126]). Before
|
||||
1. **Tool-availability probe** (defense-in-depth, [TT-2115] RC1 / [TT-2126]). Before
|
||||
dispatching any {REVIEWER_OR_AUDITOR}, verify reviewers will be able to read
|
||||
wiki artifacts (requirements / design / plan / prior-review reports). A
|
||||
reviewer that cannot read its inputs aborts or hallucinates — catch this ONCE
|
||||
in the Orchestrator instead of letting {DIMENSION_COUNT} parallel subagents
|
||||
each rediscover the gap:
|
||||
|
||||
- **Primary path**: confirm `gitea_wiki__*` tools are registered (the
|
||||
Orchestrator checks its own tool catalog; these tools are forwarded to
|
||||
reviewer subagents when registered — [org-internal #2116] raised the tool cap 50→100 so
|
||||
they are present in normal runs). If available → continue to step 2.
|
||||
- **Fallback path** (when `gitea_wiki__*` is NOT registered, e.g. a
|
||||
cross-repo scenario [org-internal #2115]): verify the **local wiki clone** at
|
||||
- **Primary path**: confirm the Gitea REST API is reachable — probe
|
||||
`GET <gitea-base-url>/api/v1/repos/{owner}/{repo}/wiki/pages` with
|
||||
`-H "Authorization: token <token>"` (a 200 or 403 response means
|
||||
reachable; anything else — timeout, connection refused, 5xx — is
|
||||
unreachable). If reachable → continue to step 2.
|
||||
- **Fallback path** (when REST is unreachable, e.g. a
|
||||
cross-repo scenario [TT-2115]): verify the **local wiki clone** at
|
||||
`<wiki-clone-root>/{repo}-wiki/` is readable —
|
||||
`glob(pattern="*.md", path="<wiki-clone-root>/{repo}-wiki/")`. If the clone
|
||||
is readable → continue to step 2; reviewers use the local clone (see
|
||||
@@ -82,13 +83,14 @@ in `_shared/gitea-write-patterns.md`.
|
||||
- **Both unavailable → FAIL FAST**: post a `failure` commit status (state
|
||||
`"failure"`, context `pipeline/{REVIEW_TYPE}`, description naming the
|
||||
missing capability) and abort — do NOT enter parallel dispatch. Report the
|
||||
gap so the environment can be fixed (register the wiki MCP server, or
|
||||
populate `<wiki-clone-root>/{repo}-wiki/`).
|
||||
gap so the environment can be fixed (restore Gitea REST reachability —
|
||||
token validity, network route — or
|
||||
populate `<wiki-clone-root>/{repo}-wiki/`).
|
||||
|
||||
This probe is belt-and-suspenders: RC1 (tool cap, [org-internal #2116]) already fixed the
|
||||
primary cause of missing `gitea_wiki__*` in subagents. It exists so a future
|
||||
environment regression fails gracefully with one clear message instead of N
|
||||
silent subagent aborts.
|
||||
This probe is belt-and-suspenders: it exists so a future
|
||||
environment regression (REST unreachable, stale token) fails gracefully
|
||||
with one clear message instead of N
|
||||
silent subagent aborts.
|
||||
|
||||
2. Post an initial pending commit status via REST:
|
||||
|
||||
@@ -264,7 +266,7 @@ Otherwise:
|
||||
- The {REVISION_ROLE} MUST NOT receive the full text of all findings inline —
|
||||
use finding-file path / comment references only to avoid context explosion.
|
||||
- Convergence status: blockers/majors remaining vs. previous round.
|
||||
- **Revision survival ([org-internal #2601]) — primary path**: the task tool's completion
|
||||
- **Revision survival ([TT-2601]) — primary path**: the task tool's completion
|
||||
output includes a `task_id`; passing it back resumes the SAME
|
||||
{REVISION_ROLE} subagent session instead of creating a fresh one. Round 1:
|
||||
persist the returned `task_id` with the round's working-notes entry (it
|
||||
@@ -320,17 +322,24 @@ After the {REVISION_ROLE} completes revision:
|
||||
`core/schemas/review-status.schema.json`).
|
||||
- `review-code` skill: **2** default / **3** high-risk (a BLOCKER survived a
|
||||
round, or the diff touches a frozen cross-session contract) —
|
||||
`<instance-root>/workflow-routing.yaml` `review.max_rounds` ([org-internal #3567], process-diet
|
||||
`<instance-root>/workflow-routing.yaml` `review.max_rounds` ([TT-3567], process-diet
|
||||
P0b). At budget without convergence: STOP, register the remaining
|
||||
BLOCKER/MAJOR findings as TD registry rows, verdict FAIL if any BLOCKER
|
||||
remains else PASS — the debt is carried by those TD registry rows
|
||||
BLOCKER/MAJOR findings as TD registry rows, then compute the verdict
|
||||
with the shared three-tier ladder (`core/schemas/synthesis.schema.json`
|
||||
`overall_verdict` + `core/skills/_shared/review-orchestrator-rules.md`
|
||||
rule 3): FAIL if any BLOCKER or FAIL dimension remains, else WARN,
|
||||
PASS only if every remaining dimension is PASS ([TT-4786]:
|
||||
the prior binary "else PASS" wording silently upgraded WARN-eligible
|
||||
outcomes to PASS; a PASS round has already stopped at the convergence
|
||||
table above, so the residual tail lands WARN or FAIL). The debt is
|
||||
carried by those TD registry rows
|
||||
(see `review-code/SKILL.md` Phase D). This
|
||||
supersedes the 2026-08-25 [org-internal #3380] calibration (p50=2, p95=5, n=66): the runs
|
||||
supersedes the 2026-08-25 [TT-3380] calibration (p50=2, p95=5, n=66): the runs
|
||||
past round 3 are the marathon tail this budget exists to cut; their residue
|
||||
flows to the TD registry instead of reviewer rounds. Ledger:
|
||||
`docs/workflow-refactor/thresholds-ledger.md`.
|
||||
|
||||
Rationale for `review-artifact` = 3 (evaluated in [org-internal #1969], replacing the prior blanket
|
||||
Rationale for `review-artifact` = 3 (evaluated in [TT-1969], replacing the prior blanket
|
||||
default of 5): (1) the Round-3 Escalation Guardrail below already detects
|
||||
non-convergence at the start of round 3; (2) the INFO-disposition rule below
|
||||
removes spurious WARN rounds previously caused by non-blocking INFO findings;
|
||||
@@ -341,8 +350,8 @@ reaches round 4 — its round budget is 2/3, see the binding above.)
|
||||
|
||||
**Provisional, not empirically validated**: the four safeguards make `review-artifact`=3
|
||||
defensible, but it has no fresh run-data yet. Treat it as a hypothesis to
|
||||
confirm via the retrospective signal ([org-internal #1834]; gate-trim's landing machinery was
|
||||
retired, [org-internal #3072] phase 3 — the check is observational, not a trim proposal): if
|
||||
confirm via the retrospective signal ([TT-1834]; gate-trim's landing machinery was
|
||||
retired, [TT-3072] phase 3 — the check is observational, not a trim proposal): if
|
||||
live `review-artifact` runs frequently hit round 3 still improving yet are
|
||||
forced to stop at WARN/FAIL, bump it back to 4.
|
||||
|
||||
@@ -370,8 +379,8 @@ block convergence and NEVER drive a reviser round.
|
||||
**Round-3 Escalation Guardrail** (applies to the `review-artifact` skill's
|
||||
live targets — the process audit target AND the review-dag single-gate
|
||||
target; the roadmap / design / plan targets were archived 2026-08-21,
|
||||
[org-internal #3072] phase 3). `review-code` does NOT use this guardrail; it uses its round
|
||||
budget ([org-internal #3567], see the `{MAX_ROUNDS}` binding above).
|
||||
[TT-3072] phase 3). `review-code` does NOT use this guardrail; it uses its round
|
||||
budget ([TT-3567], see the `{MAX_ROUNDS}` binding above).
|
||||
|
||||
At the start of round 3, if the combined blocker+major count is still >50% of
|
||||
round 1's count, STOP the loop and surface to the user:
|
||||
@@ -382,7 +391,7 @@ round 1's count, STOP the loop and surface to the user:
|
||||
> (a) Return to upstream — for the `process` audit target, escalate to the
|
||||
> octopus maintainer for a process-level redesign (the legacy producer skills
|
||||
> `roadmap` / `requirements-elicitation` / `design` / `plan-iterations` were
|
||||
> archived 2026-08-21, [org-internal #3072] phase 3 — `<instance-root>/archive/`), then restart this
|
||||
> archived 2026-08-21, [TT-3072] phase 3 — `<instance-root>/archive/`), then restart this
|
||||
> review at round 1.
|
||||
> (b) Continue iterating — accept that more rounds may be needed (capped by
|
||||
> `{MAX_ROUNDS}`).
|
||||
@@ -397,7 +406,7 @@ review and escalate to a human, or (b) continue into round 4 — via the
|
||||
`question` tool. The guard means "escalate with a choice", NOT "force-stop".
|
||||
The choice is UNCONDITIONAL at the round-3→4 transition — instance skills may
|
||||
narrow when an escalation *variant* (e.g. a design-level decision) fires, but
|
||||
never narrow the choice gate itself. The call MUST be optionized ([org-internal #3378]):
|
||||
never narrow the choice gate itself. The call MUST be optionized ([TT-3378]):
|
||||
two options — `Stop & escalate to a human` (first, when recommended) /
|
||||
`Continue into round 4` — with `stage` set to the running skill's stage so
|
||||
auto-approval applies in autonomous mode; free-text asking is a spec
|
||||
@@ -405,12 +414,12 @@ violation.
|
||||
Instance: review-dag D4 option-b (`review-artifact/SKILL.md` §"Round-3
|
||||
Escalation Guardrail interaction") — the sole live instance, its D4 round cap
|
||||
(≤4) being the only budget that reaches round 4 (`review-code` is capped 2/3,
|
||||
[org-internal #3567]).
|
||||
Rationale (retro 2026-08-21 / [org-internal #3050]): unattended late-round loops drift into
|
||||
[TT-3567]).
|
||||
Rationale (retro 2026-08-21 / [TT-3050]): unattended late-round loops drift into
|
||||
review marathons — the choice forces the design-level stall to surface to a
|
||||
human at round 4 instead of round 6.
|
||||
|
||||
**Efficiency optimization**: From round 2 onward ([org-internal #2598]), only spawn
|
||||
**Efficiency optimization**: From round 2 onward ([TT-2598]), only spawn
|
||||
{REVIEWER_OR_AUDITOR}s for dimensions that had FAIL, WARN, or UNRESOLVED in
|
||||
the previous round. Every 2 rounds, run a full {DIMENSION_COUNT}-reviewer
|
||||
sweep to catch regressions. From round 2 onward reviewer input is also
|
||||
@@ -471,11 +480,13 @@ not the round-1 full set.
|
||||
|
||||
3.5. **Gitea approval timing (mandatory when the PR needs a human approval
|
||||
gate)**: if the flow requests approval from a human reviewer on Gitea,
|
||||
register the reviewer FIRST via `gitea_pull__add_reviewer`, wait for the
|
||||
`REQUEST_REVIEW` registration to be recorded, and only THEN ask the human
|
||||
register the reviewer FIRST via
|
||||
`POST <gitea-base-url>/api/v1/repos/{owner}/{repo}/pulls/{index}/requested_reviewers`,
|
||||
wait for the
|
||||
`REQUEST_REVIEW` registration to be recorded, and only THEN ask the human
|
||||
to approve. Approving before the reviewer is registered produces
|
||||
`official: false` on the approval — the gate treats the PR as unapproved
|
||||
and the approval must be re-done. ([org-internal #1931]: audit R2→R3 re-loop + re-approve,
|
||||
and the approval must be re-done. ([TT-1931]: audit R2→R3 re-loop + re-approve,
|
||||
~30min wasted on exactly this ordering.)
|
||||
|
||||
4. Present the final report to the user and obtain approval via the `question`
|
||||
|
||||
@@ -65,7 +65,8 @@ Label: {DIMENSION_NAME}
|
||||
|
||||
## What You Must NOT Do
|
||||
|
||||
- Do NOT fabricate results. If a tool you need (e.g. `gitea_wiki__get_page`,
|
||||
- Do NOT fabricate results. If a tool you need (e.g. the Gitea REST call
|
||||
`GET <gitea-base-url>/api/v1/repos/{owner}/{repo}/wiki/pages`,
|
||||
`read`, `codegraph_*`) is unavailable, errors, or returns empty, report the
|
||||
failure honestly — emit a finding stating the dimension could not be
|
||||
reviewed due to the missing tool. NEVER invent findings, severities, or
|
||||
|
||||
@@ -31,7 +31,7 @@ After revising, report a summary of changes made:
|
||||
- Findings waived as cosmetic MINOR (round 2+): {WAIVED-{id} → reason}
|
||||
|
||||
Persist that summary to `{RETURN_FILE}` as your LAST action, BEFORE
|
||||
returning it — worker-report persistence ([org-internal #2847], see
|
||||
returning it — worker-report persistence ([TT-2847], see
|
||||
`.octopus/skills/_shared/worker-report-persistence.md`). The persisted copy
|
||||
is the report of record; if your completion notification is lost, the
|
||||
Orchestrator recovers the revision outcome from this file.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
> Core 中立版(Increment 6a 改写,原 deferHard verbatim)。编号与条目结构严格不变(C-2 不变量);实例术语按 `core/adapters/TERMINOLOGY.md` 绑定。
|
||||
name: Coordinator
|
||||
purpose: >
|
||||
Pool dispatch coordinator (billing-v2 [org-internal #4041] §7, REQ-F-012): a wake-driven,
|
||||
Pool dispatch coordinator (billing-v2 [TT-4041] §7, REQ-F-012): a wake-driven,
|
||||
STATELESS decision-maker session living in the pool pod alongside workers.
|
||||
List eligible issues (Gitea API, scoped token) → produce DAG-aware dispatch
|
||||
proposals → commit each dispatch through the N-16 assignment API
|
||||
@@ -62,14 +62,14 @@ agents_md:
|
||||
#
|
||||
# Security posture (AC-5, see docs/security/threat-model.md §自治批处理):
|
||||
# the coordinator authenticates with a workspace-level API token
|
||||
# (TD-687/[org-internal #3898] owner-minted, jti-revocable, role claim org_role). TODAY'S
|
||||
# (TD-687/[TT-3898] owner-minted, jti-revocable, role claim org_role). TODAY'S
|
||||
# mint shape hardcodes org_role=viewer — read-capable only (assignment table
|
||||
# + pool surfaces); the editor-capable mint needed for dispatch submission is
|
||||
# an explicit deployment-time decision on the [org-internal #3898] channel (not landed with
|
||||
# an explicit deployment-time decision on the [TT-3898] channel (not landed with
|
||||
# N-19). Either way the token can NOT mint tokens, touch wallet internals, or
|
||||
# merge PRs — the merge gate stays human (E-4).
|
||||
#
|
||||
# Worker-report persistence ([org-internal #2847] — see
|
||||
# Worker-report persistence ([TT-2847] — see
|
||||
# core/skills/_shared/worker-report-persistence.md): a Coordinator
|
||||
# sub-agent persists its FINAL RETURN REPORT to disk as its LAST action,
|
||||
# before returning — <runs-root>/{slug}/workers/{chunk-id}-worker-{seq}.md
|
||||
|
||||
@@ -15,7 +15,7 @@ agents_md:
|
||||
- claim-discipline
|
||||
- compact
|
||||
|
||||
# Worker-report persistence ([org-internal #2847], retro-2696 AI#2 — see
|
||||
# Worker-report persistence ([TT-2847], retro-2696 AI#2 — see
|
||||
# core/skills/_shared/worker-report-persistence.md): every Producer
|
||||
# sub-agent persists its FINAL RETURN REPORT to disk as its LAST action,
|
||||
# before returning — <runs-root>/{slug}/workers/{chunk-id}-worker-{seq}.md
|
||||
@@ -23,7 +23,7 @@ agents_md:
|
||||
# else /tmp/octopus/{chunk-id}-worker-{seq}.md. The persisted copy is the
|
||||
# report of record; the task notification is a convenience copy.
|
||||
#
|
||||
# Working-notes contract ([org-internal #2600] — see core/templates/runs-layout.md §
|
||||
# Working-notes contract ([TT-2600] — see core/templates/runs-layout.md §
|
||||
# working-notes.md): at stage exit the Producer appends ONE entry (≤30 lines:
|
||||
# decisions and why, dead ends, reviewer feedback that changed the work, hints
|
||||
# for the next stage) to <runs-root>/{slug}/working-notes.md, and registers
|
||||
|
||||
@@ -14,7 +14,7 @@ agents_md:
|
||||
- ticket-lifecycle
|
||||
- compact
|
||||
|
||||
# Working-notes contract ([org-internal #2600] — see core/templates/runs-layout.md §
|
||||
# Working-notes contract ([TT-2600] — see core/templates/runs-layout.md §
|
||||
# working-notes.md): the Reviewer side appends ONE distilled entry via the
|
||||
# Synthesizer at review convergence — never per dimension dispatch (9
|
||||
# dimension dispatches = 1 entry) — to <runs-root>/{slug}/working-notes.md.
|
||||
|
||||
@@ -12,7 +12,7 @@ agents_md:
|
||||
- claim-discipline
|
||||
- compact
|
||||
|
||||
# Working-notes contract ([org-internal #2600] — see core/templates/runs-layout.md §
|
||||
# Working-notes contract ([TT-2600] — see core/templates/runs-layout.md §
|
||||
# working-notes.md): Tool agents append to <runs-root>/{slug}/working-notes.md
|
||||
# ONLY when the task produced a load-bearing finding (e.g. image evidence that
|
||||
# changed a decision) — not for routine single-shot output.
|
||||
|
||||
@@ -15,7 +15,7 @@ agents_md:
|
||||
- claim-discipline
|
||||
- compact
|
||||
|
||||
# Worker-report persistence ([org-internal #2847], retro-2696 AI#2 — see
|
||||
# Worker-report persistence ([TT-2847], retro-2696 AI#2 — see
|
||||
# core/skills/_shared/worker-report-persistence.md): the Verifier
|
||||
# persists its FINAL RETURN REPORT (DoD verdict + evidence pointers) to disk
|
||||
# as its LAST action, before returning —
|
||||
@@ -23,7 +23,7 @@ agents_md:
|
||||
# else /tmp/octopus/{chunk-id}-worker-{seq}.md. The persisted copy is the
|
||||
# report of record; the task notification is a convenience copy.
|
||||
#
|
||||
# Working-notes contract ([org-internal #2600] — see core/templates/runs-layout.md §
|
||||
# Working-notes contract ([TT-2600] — see core/templates/runs-layout.md §
|
||||
# working-notes.md): the Verifier appends ONE entry at verify exit (what the
|
||||
# DoD sweep caught, flaky/deferral context the next run should know). The
|
||||
# Phase 5.5 archive step additionally inlines the final working-notes.md
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
- **Commit SHA**: `{SHA}` (the HEAD commit being reviewed).
|
||||
- **Review type**: `{REVIEW_TYPE}` — one of `review-code`, `review-dag`,
|
||||
`audit-process` (the `review-design-space` / `review-iteration-plan` /
|
||||
`review-roadmap` targets were archived 2026-08-21, [org-internal #3072] phase 3 — their
|
||||
`review-roadmap` targets were archived 2026-08-21, [TT-3072] phase 3 — their
|
||||
historical synthesis data remains readable).
|
||||
|
||||
## Your Job
|
||||
@@ -189,7 +189,7 @@
|
||||
9. Persist your return summary (the exact text from the Return Format
|
||||
below) to `<runs-root>/{slug}/reviews/{stage}/round{N}/synthesis-return.md`
|
||||
(Tier 1) as your LAST action, BEFORE returning it — worker-report
|
||||
persistence ([org-internal #2847], `_shared/worker-report-persistence.md`). The persisted
|
||||
persistence ([TT-2847], `_shared/worker-report-persistence.md`). The persisted
|
||||
copy is the report of record; if your completion notification is lost, the
|
||||
Orchestrator recovers the round verdict from this file.
|
||||
|
||||
@@ -211,7 +211,7 @@ synthesis JSON — it is already posted to the pipeline PR / source issue
|
||||
comment (for audit-process runs, the wiki page `audit/{date}/round{N}/synthesis`).
|
||||
Persist this summary verbatim to
|
||||
`<runs-root>/{slug}/reviews/{stage}/round{N}/synthesis-return.md` before
|
||||
returning (step 9 above — worker-report persistence [org-internal #2847]).
|
||||
returning (step 9 above — worker-report persistence [TT-2847]).
|
||||
|
||||
```
|
||||
## Synthesis Complete
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
> Canonical convention for every worker sub-agent dispatch (roles whose
|
||||
> `agent:` is `worker` — Producer sub-roles, Verifier, Synthesizer, …),
|
||||
> foreground or background (`task background=true`). Origin: retro WWW#5 /
|
||||
> [org-internal #2696] action item #2 ([org-internal #2847]) — at least one confirmed case where a
|
||||
> [TT-2696] action item #2 ([TT-2847]) — at least one confirmed case where a
|
||||
> background worker's completion report reached the orchestrating session
|
||||
> only via the task-tool notification; the notification was lost and the
|
||||
> report evaporated, leaving nothing but reverse-engineering from artifacts.
|
||||
|
||||
@@ -3,7 +3,7 @@ name: analyze-dag
|
||||
description: >
|
||||
Use ONLY when an Epic is routed to the DAG ticket pipeline (Kind/Epic or
|
||||
Kind/Feature — both resolve to analyze-dag via the routes table directly,
|
||||
[org-internal #3072] phase 3 / [org-internal #3061] Phase 2). The
|
||||
[TT-3072] phase 3 / [TT-3061] Phase 2). The
|
||||
Analyst decomposes the Epic into a single task-DAG artifact — merging
|
||||
roadmap+requirements+design+plan into one graph (nodes = acceptance
|
||||
criteria, edges = contracts, topology = plan).
|
||||
@@ -31,7 +31,7 @@ role: Producer
|
||||
analyze-dag is the **entry skill** of the DAG ticket pipeline
|
||||
(`dag.route.entry.skill`, spec-07 §2). For a DAG-routed Epic
|
||||
(`Kind/Epic`, or `Kind/Feature` — both resolve here via the routes table
|
||||
directly, [org-internal #3072] phase 3 / [org-internal #3061] Phase 2 / TD-388 —
|
||||
directly, [TT-3072] phase 3 / [TT-3061] Phase 2 / TD-388 —
|
||||
including BACKFILL mode for MVP graduates and big-bug relabels), it
|
||||
**replaces** `roadmap` + `requirements-elicitation` + `design` +
|
||||
`plan-iterations` and produces **ONE artifact**: the task DAG, published as
|
||||
@@ -66,12 +66,12 @@ a topological order (the plan), then publishes the single graph.
|
||||
| 设计主导 | 主要风险是一个有 ≥2 个可行选项的架构/平台决策,而非任务分解;需要先做一次探索 | 将开放问题转 `prototype`(THROWAWAY spike)或设计探索;决策记录后重入 |
|
||||
| 外部契约未决 | scope 依赖未决的外部契约(第三方 schema、上游 API 未定) | 按 External-System Rule(见下文)解析或围栏;不可拆的残余隔离后再重入 |
|
||||
|
||||
**反向拦截(Kind/MVP 降级建议,[org-internal #3061])**:一个 `Kind/Feature` 工单在分解预检中
|
||||
**反向拦截(Kind/MVP 降级建议,[TT-3061])**:一个 `Kind/Feature` 工单在分解预检中
|
||||
暴露"概念未稳"(scope 仍在探索、成功标准未定、决策日志会推翻节点划分)时,
|
||||
正确出口不是硬分解,而是建议改标签 `Kind/MVP` 先行交互式验证——概念稳定后
|
||||
经 backfill 模式(见下文)带着决策日志重入。
|
||||
|
||||
### Phase 0 需求澄清(disqualifier 的结构化扩展,[org-internal #3061])
|
||||
### Phase 0 需求澄清(disqualifier 的结构化扩展,[TT-3061])
|
||||
|
||||
预检不止于"能否分解",还须证明"需求已澄清到可分解"。两项强制检查:
|
||||
|
||||
@@ -217,7 +217,7 @@ Rules:
|
||||
- `refs_by` is derived from the REQMAP "every requirement ≥1 node" criterion
|
||||
(missing coverage = a requirement with no node).
|
||||
|
||||
## Breadth Coverage — 类目覆盖矩阵 + 排除账本 ([org-internal #2905] 方案 1)
|
||||
## Breadth Coverage — 类目覆盖矩阵 + 排除账本 ([TT-2905] 方案 1)
|
||||
|
||||
The four-stage fold that produced the single DAG artifact kept requirement
|
||||
**depth** (REQMAP three-path coverage + falsifiable AC) but dropped legacy
|
||||
@@ -271,7 +271,7 @@ sub-page `{epic-slug}/dag-coverage` using the same mechanics as AC sinking
|
||||
frozen copy) — purely organizational, NOT an oversize signal, no
|
||||
re-derivation.
|
||||
|
||||
### Breadth probe nodes (P2, [org-internal #2905] 方案 2)
|
||||
### Breadth probe nodes (P2, [TT-2905] 方案 2)
|
||||
|
||||
When a 待确认 category is cheapest to resolve empirically, a **probe node**
|
||||
is a legal task node at the granularity floor:
|
||||
@@ -306,12 +306,12 @@ is a legal task node at the granularity floor:
|
||||
冻结副本(新增需求必然改变节点集合或 `req_refs`;需要新节点时全额按
|
||||
node_split 建单传播)。
|
||||
|
||||
### Data layer — read `dag.route.preflight` BEFORE decomposition ([org-internal #2905] 方案 3)
|
||||
### Data layer — read `dag.route.preflight` BEFORE decomposition ([TT-2905] 方案 3)
|
||||
|
||||
Before starting decomposition, analyze-dag MUST read
|
||||
`<instance-root>/workflow-routing.yaml` `dag.route.preflight` and, when the list is
|
||||
non-empty, verify each item as a producer self-check (the same injection
|
||||
contract `implement` applies for `routes.{Kind}.preflight`, [org-internal #2599] — landed
|
||||
contract `implement` applies for `routes.{Kind}.preflight`, [TT-2599] — landed
|
||||
items carry their retro evidence in `evidence`):
|
||||
|
||||
1. Read the `dag:` block's `route.preflight` array (live yaml, repo root).
|
||||
@@ -407,7 +407,7 @@ external contract). This is what lets the REQMAP "需求覆盖" (requirement
|
||||
coverage) check mechanically verify that external-integration requirements map
|
||||
to nodes. (The `ARCH 1.1` system-context diagram is discarded only for
|
||||
process-infrastructure-type Epics; product Epics get this alternative rule
|
||||
instead.) [org-internal #2905]: this rule is the 外部系统集成 category of the breadth
|
||||
instead.) [TT-2905]: this rule is the 外部系统集成 category of the breadth
|
||||
coverage matrix held at its original strength — see Breadth Coverage above.
|
||||
|
||||
## Exec-Resource Configuration (spec-07 §4 — mechanical destination of folded checklist rows)
|
||||
@@ -433,7 +433,7 @@ observe:
|
||||
`> DAG 工件状态: draft`.
|
||||
2. After the single-gate (`review-dag`) PASS, the **aggregator agent** (main
|
||||
session / Orchestrator — not analyze-dag) asks the freeze confirmation
|
||||
question ([org-internal #3379]), then on confirmation flips the page to
|
||||
question ([TT-3379]), then on confirmation flips the page to
|
||||
`> DAG 工件状态: frozen` and stamps version `v1`. The confirmation is an
|
||||
OPTIONIZED `question` call (stage `review-dag`, never `destructive` —
|
||||
freeze is a process gate, not a business decision): options
|
||||
@@ -454,7 +454,7 @@ observe:
|
||||
the version stamp `vN → vN+1` (no re-confirmation — only the initial
|
||||
freeze gates on a decision).
|
||||
|
||||
## Backfill Input Mode (Kind/MVP graduation & big-bug relabels, [org-internal #3061])
|
||||
## Backfill Input Mode (Kind/MVP graduation & big-bug relabels, [TT-3061])
|
||||
|
||||
When a `Kind/MVP` ticket graduates (relabel → `Kind/Feature` → Step 0 → this
|
||||
skill), the DAG is derived from **what was actually built**, not from greenfield
|
||||
@@ -500,4 +500,4 @@ decomposition:
|
||||
- `dag-pipeline/spec-06` — dag_metrics derivation + thresholds
|
||||
- `dag-pipeline/spec-07` — dag.route landing row (entry skill, skip set, single-gate) + §4 landing list
|
||||
- `dag-pipeline/spec-08` — DAG artifact lifecycle / version stamp
|
||||
- `<instance-root>/archive/skills/roadmap/SKILL.md` — legacy route (archived 2026-08-21, [org-internal #3072] phase 3; this skill replaces it for all Epics)
|
||||
- `<instance-root>/archive/skills/roadmap/SKILL.md` — legacy route (archived 2026-08-21, [TT-3072] phase 3; this skill replaces it for all Epics)
|
||||
|
||||
@@ -185,7 +185,7 @@ When a `verify` work item has an E2E or UI DoD entry:
|
||||
## Session cleanup (mandatory)
|
||||
|
||||
A Playwright MCP browser is a real Chrome with a `/tmp` user-data-dir — its
|
||||
mode follows `mcp.playwright.headless` (`headless-field-v1`, [org-internal #4393]): the repo
|
||||
mode follows `mcp.playwright.headless` (`headless-field-v1`, [TT-4393]): the repo
|
||||
default `auto` spawns headed on desktop (win32/darwin; linux only with
|
||||
DISPLAY/WAYLAND_DISPLAY set) and headless otherwise; an explicit `true`/`false`
|
||||
or `OCTOPUS_MCP_HEADLESS=1|0` pins it. The mode is fixed per new session —
|
||||
@@ -194,7 +194,7 @@ stays alive as long as its MCP server runs, and the MCP server stays alive as
|
||||
long as its parent octopus backend runs. When a browser-debug session ends
|
||||
without an explicit `browser_close`, OR the octopus session times out mid-task,
|
||||
the Chrome + its MCP server are orphaned and accumulate across sessions —
|
||||
burning CPU and leaving dead profile dirs (issue [org-internal #1315]); in headed mode the
|
||||
burning CPU and leaving dead profile dirs (issue [TT-1315]); in headed mode the
|
||||
orphan is a visible stray window.
|
||||
|
||||
**Iron rule: every browser-debug session MUST close its browser before ending.**
|
||||
|
||||
@@ -171,7 +171,7 @@ Disable the watcher on slow filesystems (WSL2 `/mnt` drives, network mounts):
|
||||
codegraph serve --mcp --no-watch
|
||||
```
|
||||
|
||||
### Workflow worktrees get their own index ([org-internal #2561] / TD-006)
|
||||
### Workflow worktrees get their own index ([TT-2561] / TD-006)
|
||||
|
||||
The main checkout's `.codegraph/` does NOT cover git worktrees — they live
|
||||
outside the repo path, so nearest-`.codegraph/` resolution finds nothing under
|
||||
|
||||
@@ -315,7 +315,7 @@ Present the report to the user. Route to code review if > 20 lines or ≥ 3 file
|
||||
- `core/checklists/frontend.md` — Frontend self-check checklist
|
||||
- `core/skills/implement/SKILL.md` — General + pipeline implementation workflow
|
||||
- `core/skills/review-code/SKILL.md` — Code review (next step)
|
||||
- `<instance-root>/archive/skills/design/SKILL.md` — Design document production (legacy upstream, archived [org-internal #3072] phase 3)
|
||||
- `<instance-root>/archive/skills/design/SKILL.md` — Design document production (legacy upstream, archived [TT-3072] phase 3)
|
||||
- `core/skills/browser-debug/SKILL.md` — Interactive browser verification (invoke during Phase 3 / 4 for visual + interaction evidence)
|
||||
- `core/rules/testing.md`, `core/rules/type-checking.md` — Repository conventions (test commands, typecheck)
|
||||
- `core/rules/code-graph.md` — Code graph first
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: gitea-rest
|
||||
description: Use ONLY when an agent must call the Gitea REST API over HTTP (curl / fetch / HttpClient) 鈥?not for other gitea tooling (the retired gitea-mcp wrapper / gitea_* MCP tools). Covers auth schemes + token scopes, pagination, error format, this fork's specifics, copy-paste recipes for the daily loop (issues, PRs, comments, labels, releases, raw files), and the on-demand recipe for extracting any endpoint's definition from the auto-generated swagger spec (`/swagger.v1.json`) instead of keeping an endpoint catalog in context. This is the only supported Gitea API path 鈥?the gitea-mcp wrapper is retired.
|
||||
description: Use ONLY when an agent must call the Gitea REST API over HTTP (curl / fetch / HttpClient) — not for other gitea tooling (the retired gitea-mcp wrapper / gitea_* MCP tools). Covers auth schemes + token scopes, pagination, error format, this fork's specifics, copy-paste recipes for the daily loop (issues, PRs, comments, labels, releases, raw files), and the on-demand recipe for extracting any endpoint's definition from the auto-generated swagger spec (`/swagger.v1.json`) instead of keeping an endpoint catalog in context. This is the only supported Gitea API path — the gitea-mcp wrapper is retired.
|
||||
triggers:
|
||||
# Direct Gitea HTTP/REST. Composite "gitea rest"/"gitea api" to avoid
|
||||
# colliding with other gitea tooling.
|
||||
@@ -11,20 +11,20 @@ triggers:
|
||||
- /api/v1
|
||||
- gitea swagger
|
||||
- swagger.v1.json
|
||||
- 璋?gitea api
|
||||
- gitea 鎺ュ彛
|
||||
- 调gitea api
|
||||
- gitea 接口
|
||||
- gitea rest api
|
||||
role: Producer
|
||||
---
|
||||
|
||||
> Core 涓珛鐗堬紙Increment 6a 鏀瑰啓锛夈€傛湰鏂囦欢鍚屾椂浣滀负 gitea adapter 鐨?**reference implementation** 绀轰緥锛坒rontmatter 鍘熸牱锛夛紱瀹炰緥鏈瀵圭収 `core/adapters/TERMINOLOGY.md`銆?
|
||||
# Gitea REST 鈥?conventions + on-demand endpoint lookup
|
||||
> Core 中立版(Increment 6a 改写)。本文件同时作为 gitea adapter 的 **reference implementation** 示例(frontmatter 原样);实例术语对照 `core/adapters/TERMINOLOGY.md`。
|
||||
# Gitea REST — conventions + on-demand endpoint lookup
|
||||
|
||||
Gitea ships a JSON REST API under **`/api/v1`**. The instance also publishes an
|
||||
**auto-generated OpenAPI spec at `/swagger.v1.json`** (~889KB, 316 endpoints) 鈥?
|
||||
**auto-generated OpenAPI spec at `/swagger.v1.json`** (~889KB, 316 endpoints) —
|
||||
never load it whole into context; extract single endpoint definitions with jq
|
||||
(see "Endpoint lookup"). The spec is generated from this fork's code, so it is
|
||||
always current 鈥?no manually maintained catalog can drift.
|
||||
always current — no manually maintained catalog can drift.
|
||||
|
||||
## Quick start
|
||||
|
||||
@@ -37,7 +37,7 @@ curl -fsS -H "$AUTH" $BASE/api/v1/version # => {"version":"1.22.0"}
|
||||
|
||||
Inside a workspace container: `WORKSPACE_GIT_TOKEN` already carries the
|
||||
provisioned token, and the instance host resolves to the VPC-internal address
|
||||
(no EIP bandwidth cap) 鈥?use it as `TOKEN` directly.
|
||||
(no EIP bandwidth cap) — use it as `TOKEN` directly.
|
||||
|
||||
## Authentication
|
||||
|
||||
@@ -47,7 +47,7 @@ provisioned token, and the instance host resolves to the VPC-internal address
|
||||
| OAuth2 JWT | `Authorization: bearer <jwt>` | OAuth2-app token. |
|
||||
| Basic | `Authorization: Basic <base64(user:pass)>` | Server must enable it; 2FA needs `X-Gitea-OTP`. |
|
||||
|
||||
- Query-param token (`?token=`) is deprecated 鈥?avoid.
|
||||
- Query-param token (`?token=`) is deprecated — avoid.
|
||||
- `Sudo: <username>` header acts as another user (admin only).
|
||||
- Keep tokens out of git and out of process argv where possible: read from a
|
||||
file/env into a shell var at call time, not in a committed script.
|
||||
@@ -55,21 +55,21 @@ provisioned token, and the instance host resolves to the VPC-internal address
|
||||
## Token scopes (write implies read)
|
||||
|
||||
Categories: `issue`, `repository`, `organization`, `user`, `notification`,
|
||||
`package`, `admin`, `misc`, `activitypub` 鈥?each as `read:X` / `write:X`.
|
||||
HTTP method sets the level: **GET 鈫?read**, **POST/PUT/PATCH/DELETE 鈫?write**.
|
||||
`package`, `admin`, `misc`, `activitypub` — each as `read:X` / `write:X`.
|
||||
HTTP method sets the level: **GET → read**, **POST/PUT/PATCH/DELETE → write**.
|
||||
A scope miss returns `403` with `token does not have at least one of required
|
||||
scope(s)...` 鈥?re-issue the token rather than widening other permissions.
|
||||
scope(s)...` — re-issue the token rather than widening other permissions.
|
||||
|
||||
The full agent loop (push commits, create/merge PRs, comment) needs at minimum
|
||||
**`write:repository` + `write:issue`**. Workspace container tokens are
|
||||
provisioned `read:repository` by default 鈥?write operations fail with 403
|
||||
provisioned `read:repository` by default — write operations fail with 403
|
||||
until the operator widens the scope.
|
||||
|
||||
## Pagination
|
||||
|
||||
- `page` (1-based, default 1), `limit` (default 30, **hard cap 50**).
|
||||
- `X-Total-Count` response header = total results.
|
||||
- `Link: <url?page=2>; rel="next"` 鈥?walk `next` links until absent.
|
||||
- `Link: <url?page=2>; rel="next"` — walk `next` links until absent.
|
||||
- Some endpoints (commits, pulls) also set `X-Page` / `X-PerPage` /
|
||||
`X-PageCount` / `X-HasMore`.
|
||||
|
||||
@@ -78,12 +78,12 @@ until the operator widens the scope.
|
||||
Every error is `{"message":"...","url":".../api/swagger"}` with the matching
|
||||
status: `400` bad arg, `403` permission/scope, `404` not found or wrong BASE,
|
||||
`409` already exists, `413` too large, `422` malformed JSON / missing field.
|
||||
There is **no rate limiting** on `/api/v1` 鈥?don't expect `X-RateLimit-*`.
|
||||
There is **no rate limiting** on `/api/v1` — don't expect `X-RateLimit-*`.
|
||||
|
||||
## Endpoint lookup (swagger, on demand)
|
||||
|
||||
For any endpoint not covered by the recipes below, pull the spec once per
|
||||
session and jq out just the definition you need (50鈥?00 tokens each):
|
||||
session and jq out just the definition you need (50–200 tokens each):
|
||||
|
||||
```sh
|
||||
curl -s $BASE/swagger.v1.json -o /tmp/gitea-sw.json
|
||||
@@ -109,7 +109,7 @@ curl -fsS -X POST "$BASE/api/v1/repos/$OWNER/$REPO/issues" -H "$AUTH" -H 'Conten
|
||||
-d '{"title":"Bug: X fails","body":"steps...","labels":[12]}'
|
||||
```
|
||||
|
||||
**Comment on an issue / PR** (same path for both 鈥?PRs are issues by index)
|
||||
**Comment on an issue / PR** (same path for both — PRs are issues by index)
|
||||
|
||||
```sh
|
||||
curl -fsS -X POST "$BASE/api/v1/repos/$OWNER/$REPO/issues/42/comments" -H "$AUTH" \
|
||||
@@ -130,48 +130,48 @@ curl -fsS -X POST "$BASE/api/v1/repos/$OWNER/$REPO/pulls/7/merge" -H "$AUTH" -H
|
||||
-d '{"Do":"merge","MergeTitleField":"feat: add X","MergeMessageField":"closes #7"}'
|
||||
```
|
||||
|
||||
**Merge returned 405? Read the response body 鈥?two distinct causes:**
|
||||
**Merge returned 405? Read the response body — two distinct causes:**
|
||||
|
||||
- `{"message":"head branch is behind the base branch"}` 鈥?the keep-mergeable
|
||||
- `{"message":"head branch is behind the base branch"}` — the keep-mergeable
|
||||
bot advanced main after your push, or Gitea's mergeable cache is stale.
|
||||
Fix: `git fetch origin main && git merge origin/main && git push` the head
|
||||
branch, wait ~2s, retry the merge. (Recurring on this server 鈥?seen 3 PRs
|
||||
branch, wait ~2s, retry the merge. (Recurring on this server — seen 3 PRs
|
||||
in a row on 2026-08-23.)
|
||||
- `{"message":"The PR is already merged"}` 鈥?**treat as success**. The merge
|
||||
- `{"message":"The PR is already merged"}` — **treat as success**. The merge
|
||||
landed during a previous "failed" attempt (racy async recompute). Confirm
|
||||
with `GET .../pulls/7 | jq '.merged, .merge_commit_sha'` before assuming
|
||||
failure. Never re-push/re-create the PR on this signal.
|
||||
|
||||
**Auth hygiene** 鈥?always pass the token via the `Authorization` header
|
||||
**Auth hygiene** — always pass the token via the `Authorization` header
|
||||
(`-H "Authorization: token $TOKEN"`), never embedded in a remote URL
|
||||
(`https://user:token@host/...`): it persists into `.git/config` and shell
|
||||
history. If a token leaks into a remote URL, rewrite the remote
|
||||
(`git remote set-url`) and rotate.
|
||||
|
||||
**List PRs / changed files** 鈥?`GET .../pulls?state=open`, `GET .../pulls/7/files`
|
||||
**List PRs / changed files** — `GET .../pulls?state=open`, `GET .../pulls/7/files`
|
||||
|
||||
**Search issues across repos** 鈥?`GET $BASE/api/v1/repos/issues/search?q=&type=pulls`
|
||||
**Search issues across repos** — `GET $BASE/api/v1/repos/issues/search?q=&type=pulls`
|
||||
|
||||
**List labels** 鈥?`GET .../labels?limit=50 | jq '.[] | {name,color}'` (label create/update via POST/PATCH on the same path)
|
||||
**List labels** — `GET .../labels?limit=50 | jq '.[] | {name,color}'` (label create/update via POST/PATCH on the same path)
|
||||
|
||||
**Raw file contents** 鈥?`GET .../raw/README.md` (plain text; the `contents/{path}` variant returns base64 in `.content`)
|
||||
**Raw file contents** — `GET .../raw/README.md` (plain text; the `contents/{path}` variant returns base64 in `.content`)
|
||||
|
||||
**Create a release** 鈥?`POST .../releases {"tag_name":"v1.2.0","target":"main",...}`
|
||||
**Create a release** — `POST .../releases {"tag_name":"v1.2.0","target":"main",...}`
|
||||
|
||||
**Create a wiki page** 鈥?`POST .../wiki/new {"title":"My Page","content_base64":"<b64>","message":"add page"}`. **`content_base64` is the ONLY field that writes body text** 鈥?this fork **silently ignores** the upstream-style `content` field on wiki create/update (no error, `201` returned, page saved 0 bytes; evidence [org-internal #3944]: commits f5eaf18/4f0217d/bad5880). `content` is valid only on the file API, never on wiki.
|
||||
**Create a wiki page** — `POST .../wiki/new {"title":"My Page","content_base64":"<b64>","message":"add page"}`. **`content_base64` is the ONLY field that writes body text** — this fork **silently ignores** the upstream-style `content` field on wiki create/update (no error, `201` returned, page saved 0 bytes; evidence [TT-3944]: commits f5eaf18/4f0217d/bad5880). `content` is valid only on the file API, never on wiki.
|
||||
|
||||
**Read / edit / delete a wiki page** 鈥?`GET|PATCH|DELETE .../wiki/page/{pageName}`. **Read by the mangled name, not the logical title**: this fork rewrites stored filenames for titles containing `/`, spaces, or `:` (slash percent-encoded into the filename + a `.-` suffix 鈥?see [org-internal #3218]), so `GET /wiki/page/bugfix-3204/bugfix-report` 404s. Always `GET .../wiki/pages` first and use the returned `sub_url` **verbatim** (it already carries the `%2F` encoding and `.-` suffix). PATCH/DELETE take the same mangled `pageName`. For PATCH, **omit `title` to keep the page name** and send only `content_base64`+`message` (fixed in gitea `dev-421-g7ff56aec08`, [org-internal #3510] 鈥?before that a title-less PATCH silently renamed the page to `unnamed.md` and later edits deleted target pages). Same trap as create: a PATCH carrying `content` instead of `content_base64` returns `200` with a **0-byte page** ([org-internal #3944]) 鈥?always base64-encode the body and verify non-empty via a follow-up `GET`.
|
||||
**Read / edit / delete a wiki page** — `GET|PATCH|DELETE .../wiki/page/{pageName}`. **Read by the mangled name, not the logical title**: this fork rewrites stored filenames for titles containing `/`, spaces, or `:` (slash percent-encoded into the filename + a `.-` suffix — see [TT-3218]), so `GET /wiki/page/bugfix-3204/bugfix-report` 404s. Always `GET .../wiki/pages` first and use the returned `sub_url` **verbatim** (it already carries the `%2F` encoding and `.-` suffix). PATCH/DELETE take the same mangled `pageName`. For PATCH, **omit `title` to keep the page name** and send only `content_base64`+`message` (fixed in gitea `dev-421-g7ff56aec08`, [TT-3510] — before that a title-less PATCH silently renamed the page to `unnamed.md` and later edits deleted target pages). Same trap as create: a PATCH carrying `content` instead of `content_base64` returns `200` with a **0-byte page** ([TT-3944]) — always base64-encode the body and verify non-empty via a follow-up `GET`.
|
||||
|
||||
## This fork's specifics
|
||||
|
||||
- **Projects are repo-level only** 鈥?no `/orgs/.../projects` or `/users/.../projects` REST endpoints.
|
||||
- **Aggregated inline review comments**: no single list-all endpoint 鈥?list
|
||||
- **Projects are repo-level only** — no `/orgs/.../projects` or `/users/.../projects` REST endpoints.
|
||||
- **Aggregated inline review comments**: no single list-all endpoint — list
|
||||
reviews, then fetch each review's `/comments`.
|
||||
- Wiki REST = 6 method脳path combos on 4 paths (`new`, `page/{pageName}`
|
||||
- Wiki REST = 6 method×path combos on 4 paths (`new`, `page/{pageName}`
|
||||
GET/PATCH/DELETE, `pages`, `revisions/{pageName}`). This fork has **no**
|
||||
upstream `raw/{pageName}` or `pages/{pageName}` single-page endpoints, and
|
||||
`page/{pageName}` only matches the mangled filename (see the wiki recipe
|
||||
above and [org-internal #3218]) 鈥?clone the wiki git repo (default branch `main`) only if
|
||||
above and [TT-3218]) — clone the wiki git repo (default branch `main`) only if
|
||||
you need history beyond `/wiki/revisions` or bulk filename surgery.
|
||||
- The authoritative route table is `routers/api/v1/api.go` in the Gitea
|
||||
source; the human-readable docs UI is `<BASE>/api/swagger`.
|
||||
@@ -180,4 +180,4 @@ history. If a token leaks into a remote URL, rewrite the remote
|
||||
|
||||
Prefer `HttpClient` from `@effect/platform` with the same headers (see
|
||||
`rules/effect-rules` on the wiki). Outside Effect, `curl` / `Bun.fetch` are
|
||||
fine 鈥?the wire format is identical.
|
||||
fine — the wire format is identical.
|
||||
|
||||
@@ -1,95 +1,95 @@
|
||||
---
|
||||
name: headless-session-ops
|
||||
description: >
|
||||
Use ONLY when an agent must autonomously launch a headless main session 鈥?
|
||||
Use ONLY when an agent must autonomously launch a headless main session —
|
||||
create a session and drive agent generation over the HTTP `prompt_async`
|
||||
endpoint with NO persistent client attached (Web UI / TUI absent) 鈥?OR
|
||||
endpoint with NO persistent client attached (Web UI / TUI absent) — OR
|
||||
lifecycle-manage such a session afterwards: health-check polling, hung-stream
|
||||
diagnosis (state=generating + frozen message count), abort + re-wake rescue,
|
||||
provider quota-wall recovery (worker killed mid-task by a usage limit 鈥?
|
||||
provider quota-wall recovery (worker killed mid-task by a usage limit —
|
||||
detect, re-wake on a known-good provider, inject facts), and fact-baseline
|
||||
injection to correct a stale worldview in a woken worker.
|
||||
This is the path used by in-session agents spawning sibling sessions,
|
||||
`octopus run --attach` non-interactive mode, and cron / CI drivers. Covers
|
||||
the 3-step flow (create session 鈫?POST prompt_async WITH a known-good
|
||||
`model` 鈫?poll `/session/:id/message` to verify generation), how to REUSE
|
||||
the 3-step flow (create session → POST prompt_async WITH a known-good
|
||||
`model` → poll `/session/:id/message` to verify generation), how to REUSE
|
||||
the current session's model for the new session, the model-field
|
||||
requirement, the directory default (current session's directory unless
|
||||
targeting another repo), and the ticket-driven recipe (launch a session
|
||||
seeded from issue #N). Do NOT use when a persistent client (Web UI / TUI)
|
||||
is driving the session 鈥?those use the synchronous `prompt` endpoint and
|
||||
is driving the session — those use the synchronous `prompt` endpoint and
|
||||
always send `model`.
|
||||
triggers:
|
||||
# English 鈥?the brand phrases for headless launch.
|
||||
# English — the brand phrases for headless launch.
|
||||
- headless session
|
||||
- launch session
|
||||
- prompt_async
|
||||
- prompt async
|
||||
- autonomous session
|
||||
# English 鈥?the failure mode (agent sees a stalled session and needs to know why).
|
||||
# English — the failure mode (agent sees a stalled session and needs to know why).
|
||||
- session not generating
|
||||
- session generation stuck
|
||||
# English 鈥?ticket-driven launch.
|
||||
# English — ticket-driven launch.
|
||||
- launch session for issue
|
||||
- launch session for ticket
|
||||
- spawn session for ticket
|
||||
# English 鈥?patrol mode (delayed self-wake polling loops, [org-internal #3937]).
|
||||
# English — patrol mode (delayed self-wake polling loops, [TT-3937]).
|
||||
- patrol loop
|
||||
- patrol mode
|
||||
- delayed wake
|
||||
# Chinese 鈥?bare noun phrases (matches() is a contiguous substring).
|
||||
- 鎷夎捣涓讳細璇?
|
||||
- 鎷夎捣浼氳瘽
|
||||
- 鑷不浼氳瘽
|
||||
- 鏃犲ご浼氳瘽
|
||||
# Chinese 鈥?patrol mode ([org-internal #3937]).
|
||||
- 宸℃妯″紡
|
||||
- 寤惰繜鍞ら啋
|
||||
- 浼氳瘽涓嶇敓鎴?
|
||||
- 浼氳瘽鍗℃
|
||||
- 涓哄伐鍗曟媺璧蜂細璇?
|
||||
- 宸ュ崟鎷夎捣浼氳瘽
|
||||
# English 鈥?lifecycle (hung rescue, stale-worldview correction, [org-internal #2459]).
|
||||
# Chinese — bare noun phrases (matches() is a contiguous substring).
|
||||
- 拉起主会话
|
||||
- 拉起会话
|
||||
- 自治会话
|
||||
- 无头会话
|
||||
# Chinese — patrol mode ([TT-3937]).
|
||||
- 巡检模式
|
||||
- 延迟唤醒
|
||||
- 会话不生成
|
||||
- 会话卡死
|
||||
- 为工单拉起会话
|
||||
- 工单拉起会话
|
||||
# English — lifecycle (hung rescue, stale-worldview correction, [TT-2459]).
|
||||
- abort session
|
||||
- revive session
|
||||
- session rescue
|
||||
- fact baseline
|
||||
# English 鈥?quota-wall recovery ([org-internal #3669]): worker killed by provider usage limit.
|
||||
# English — quota-wall recovery ([TT-3669]): worker killed by provider usage limit.
|
||||
- quota wall
|
||||
- usage limit reached
|
||||
- quota exhausted
|
||||
- switch provider
|
||||
# Chinese 鈥?lifecycle ops ([org-internal #2459]).
|
||||
- 鍞ら啋浼氳瘽
|
||||
- 浼氳瘽鎸傛
|
||||
- 浜嬪疄鍩虹嚎
|
||||
# Chinese 鈥?quota-wall recovery ([org-internal #3669]).
|
||||
- 閰嶉澧?
|
||||
- 閰嶉鑰楀敖
|
||||
- 鐢ㄩ噺涓婇檺
|
||||
- 鎹緵搴斿晢
|
||||
# Chinese — lifecycle ops ([TT-2459]).
|
||||
- 唤醒会话
|
||||
- 会话挂死
|
||||
- 事实基线
|
||||
# Chinese — quota-wall recovery ([TT-3669]).
|
||||
- 配额墙
|
||||
- 配额耗尽
|
||||
- 用量上限
|
||||
- 换供应商
|
||||
role: Producer
|
||||
---
|
||||
|
||||
> Core 涓珛鐗堬紙Increment 6a 鏀瑰啓锛屽師 deferHard verbatimDir锛夈€傛満鍒躲€佺粨鏋勪笌 frontmatter 淇濇寔锛涘疄渚嬫湳璇紙宸ュ叿鍚嶃€佽矾寰勩€佸伐鍗曞彿锛夋寜 `core/adapters/TERMINOLOGY.md` 缁戝畾鍒板叿浣撳疄渚嬨€?
|
||||
> Core 中立版(Increment 6a 改写,原 deferHard verbatimDir)。机制、结构与 frontmatter 保持;实例术语(工具名、路径、工单号)按 `core/adapters/TERMINOLOGY.md` 绑定到具体实例。
|
||||
# Headless Main Session Launch (prompt_async)
|
||||
|
||||
Launch a **main session for a specific issue / work item from a headless
|
||||
context** 鈥?no Web UI, no TUI, just HTTP. This is the "fire-and-forget" path: an
|
||||
context** — no Web UI, no TUI, just HTTP. This is the "fire-and-forget" path: an
|
||||
agent inside another session, a cron job, a CI script, or `octopus run --attach`
|
||||
non-interactive mode all land here when they need to spin up a session that
|
||||
actually generates.
|
||||
|
||||
## Directory convention 鈥?independent session in the current workspace, no worktree
|
||||
## Directory convention — independent session in the current workspace, no worktree
|
||||
|
||||
The default is an **independent session sharing the current session's
|
||||
directory** 鈥?the repo you are already working in. No new worktree, no
|
||||
directory** — the repo you are already working in. No new worktree, no
|
||||
checkout, no extra `bun install` or `.codegraph/` rebuild. Session creation
|
||||
and worktree discipline are **orthogonal**: this skill only opens a session
|
||||
record pointed at a directory; whether the launched session later creates its
|
||||
own worktree is a _workflow_ decision (per the worktree-discipline rule) it
|
||||
makes when it starts actual work 鈥?not something the launcher does. One
|
||||
exception: the **ticket-driven recipe** below, where claim-first ([org-internal #2297])
|
||||
makes when it starts actual work — not something the launcher does. One
|
||||
exception: the **ticket-driven recipe** below, where claim-first ([TT-2297])
|
||||
requires the launcher to push the workflow branch before launch, making a
|
||||
pre-built worktree the claim carrier + ready workspace (see Pitfall #10
|
||||
carve-out). So, unless a different repo / path is specifically targeted,
|
||||
@@ -100,7 +100,7 @@ carve-out). So, unless a different repo / path is specifically targeted,
|
||||
from your own session record via `GET /session/$LAUNCHER_SID`). The new
|
||||
session runs independently in that same workspace. Pass an explicit
|
||||
different `?directory=` only when the new session must work in another
|
||||
**repo** 鈥?never a worktree of the same repo. The Web UI sidebar groups
|
||||
**repo** — never a worktree of the same repo. The Web UI sidebar groups
|
||||
sessions by directory (`sidebar-project.tsx` per-workspace
|
||||
`workspaceSessions(directory)`, fetched via `session.list({ directory })`),
|
||||
so a session pointed at a worktree disappears from the workspace the creator
|
||||
@@ -109,36 +109,36 @@ carve-out). So, unless a different repo / path is specifically targeted,
|
||||
- **No current session** (cron / CI / bare script): the server-side fallback
|
||||
when `?directory=` is omitted is the **server process's `process.cwd()`**
|
||||
(`server/routes/instance/httpapi/middleware/workspace-routing.ts:76`), which
|
||||
is wherever the server was started 鈥?unreliable. In that context `?directory=`
|
||||
is wherever the server was started — unreliable. In that context `?directory=`
|
||||
remains effectively required.
|
||||
- **Dispatch convention 鈥?directory = code location, not tracker repo.** When
|
||||
- **Dispatch convention — directory = code location, not tracker repo.** When
|
||||
launching a session for a ticket, set `?directory=` to the **main workspace**
|
||||
checkout that holds the **code the ticket edits**, which may differ from the
|
||||
repo where the ticket is tracked. Example: `<owner>/<backend-repo>#<n>` is filed in
|
||||
the ticket-tracker repo but edits the main repo's workflow files 鈫?the
|
||||
the ticket-tracker repo but edits the main repo's workflow files → the
|
||||
session's `?directory=` is the **code checkout root**
|
||||
(`<workspace-root>/<org>/<repo>`), not the tracker repo checkout. Never point
|
||||
`?directory=` at a ticket worktree 鈥?the worktree goes in the claim comment +
|
||||
`?directory=` at a ticket worktree — the worktree goes in the claim comment +
|
||||
seed prompt, not the directory field (sidebar visibility, see bullet 1). The
|
||||
owner-check (`GET /session?directory=$DIR`) is scoped per directory, so
|
||||
rooting the session at the correct code checkout is also what makes the
|
||||
duplicate-session guard meaningful. Server-side backstop ([org-internal #3190]): creating a
|
||||
duplicate-session guard meaningful. Server-side backstop ([TT-3190]): creating a
|
||||
session whose directory IS a linked git worktree answers with an
|
||||
`X-Session-Directory-Warning` response header and a server warn log naming
|
||||
the owning main repo 鈥?if you see that header, the session will be invisible
|
||||
the owning main repo — if you see that header, the session will be invisible
|
||||
to `GET /session?directory=<mainRepo>` owner-checks; re-check your launch
|
||||
parameters before proceeding.
|
||||
|
||||
> **Authoritative reference:** `rules/headless-session-ops` wiki page
|
||||
> (<<instance-base-url>/Octopus/octopus/wiki/rules%2Fheadless-session-ops>).
|
||||
> This skill is its runtime carrier. Provenance: issue **[org-internal #1695]** (which
|
||||
> corrected the misdiagnosed [org-internal #1691], see comment 9205). Code citations below were
|
||||
> This skill is its runtime carrier. Provenance: issue **[TT-1695]** (which
|
||||
> corrected the misdiagnosed [TT-1691], see comment 9205). Code citations below were
|
||||
> verified against `<harness-package>` at HEAD.
|
||||
|
||||
## The `model` field 鈥?always provide a known-good model (read this first)
|
||||
## The `model` field — always provide a known-good model (read this first)
|
||||
|
||||
`prompt_async` is **fire-and-forget**: after HTTP returns 204 (or 202 when the
|
||||
message is queued behind a wedge/zombie session 鈥?no live runner in that
|
||||
message is queued behind a wedge/zombie session — no live runner in that
|
||||
process), the server runs the full agent loop in a separate fiber. **Always
|
||||
include an explicit `model`
|
||||
in the payload, and reuse the current session's model for it** (see the next
|
||||
@@ -154,7 +154,7 @@ section). Two reasons:
|
||||
// ^^^^^^^^^ agent ^^^^^^^^^^^^^^^^^ session/default
|
||||
```
|
||||
|
||||
So omission does **not** produce a clean validation error 鈥?it silently
|
||||
So omission does **not** produce a clean validation error — it silently
|
||||
resolves to the agent's model, the session's last-used model, or the
|
||||
provider default (`currentModel`, `prompt.ts:824-838`).
|
||||
|
||||
@@ -164,15 +164,15 @@ section). Two reasons:
|
||||
(`prompt.ts:1399`, `:804-822`). In the **async** handler that error is caught
|
||||
by the delivery fork's failure handling (`forkPromptDelivery` in
|
||||
`handlers/session.ts`) and never reaches the HTTP
|
||||
caller 鈥?so the session looks healthy (HTTP 204, user message persisted) yet
|
||||
caller — so the session looks healthy (HTTP 204, user message persisted) yet
|
||||
**never generates**. This is exactly the "silent stall" observed empirically
|
||||
in [org-internal #1695]: a session with a 1-message transcript (user only) and frozen
|
||||
in [TT-1695]: a session with a 1-message transcript (user only) and frozen
|
||||
`time.updated`.
|
||||
|
||||
| payload | result |
|
||||
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `{agent, parts}` 鈥?no `model` | 204/202; model filled by fallback; if the resolved model is unusable 鈫?**apparent silent stall** (no error surfaced, no generation). |
|
||||
| `{agent, model:{providerID,modelID}, parts}` | 204/202; deterministic generation within seconds (verified: "1+1 绛変簬 2銆? in ~6s). |
|
||||
| `{agent, parts}` — no `model` | 204/202; model filled by fallback; if the resolved model is unusable → **apparent silent stall** (no error surfaced, no generation). |
|
||||
| `{agent, model:{providerID,modelID}, parts}` | 204/202; deterministic generation within seconds (verified: "1+1 等于 2。 in ~6s). |
|
||||
|
||||
> **Iron Law:** every `prompt_async` payload MUST carry a **known-good** `model`,
|
||||
> and the safest known-good model is **the one driving this session right now**
|
||||
@@ -181,14 +181,14 @@ section). Two reasons:
|
||||
|
||||
**Field-name gotcha when copying a model:** the prompt payload's `ModelRef` uses
|
||||
`{ providerID, modelID }` (`prompt.ts:1852-1855`), but the **session record's**
|
||||
model uses `{ id, providerID, variant }` (`session.ts:256-260`) 鈥?i.e. `modelID`
|
||||
model uses `{ id, providerID, variant }` (`session.ts:256-260`) — i.e. `modelID`
|
||||
is called `id`. When you reuse a model read from a session record, remap
|
||||
`model.id 鈫?modelID` (see recipe below). User-message `info.model` already uses
|
||||
`model.id → modelID` (see recipe below). User-message `info.model` already uses
|
||||
`modelID` (`message.ts:403-407`).
|
||||
|
||||
## Reuse the current session's model (recommended default)
|
||||
|
||||
The model powering the launching session is proven to work 鈥?reuse it. Discover
|
||||
The model powering the launching session is proven to work — reuse it. Discover
|
||||
it by whichever path fits your context:
|
||||
|
||||
- **You are an in-session agent** (most common): read it straight from your own
|
||||
@@ -196,27 +196,27 @@ it by whichever path fits your context:
|
||||
|
||||
> "You are powered by the model named **{modelID}** (provider: **{providerID}**)."
|
||||
|
||||
e.g. `modelID = "glm-5.2"`, `providerID = "zai-coding-plan"`锛堟浘鍚?
|
||||
zhipuai-coding-plan锛?026-08 鏇村悕锛?
|
||||
e.g. `modelID = "glm-5.2"`, `providerID = "zai-coding-plan"`(曾名
|
||||
zhipuai-coding-plan,2026-08 更名)
|
||||
|
||||
- **Programmatic / no system prompt** (cron, CI, sibling caller): `GET` the
|
||||
launching session's record and read `.model`:
|
||||
|
||||
```sh
|
||||
curl -s "$BASE/session/$LAUNCHER_SID?directory=$DIR" \
|
||||
| jq '.model' # 鈫?{ "id": "glm-5.2", "providerID": "zai-coding-plan", "variant": ... }
|
||||
| jq '.model' # → { "id": "glm-5.2", "providerID": "zai-coding-plan", "variant": ... }
|
||||
```
|
||||
|
||||
Then **remap** `model.id 鈫?modelID` when building the payload.
|
||||
Then **remap** `model.id → modelID` when building the payload.
|
||||
|
||||
- **Verify the provider is actually connected** before launching (cheap
|
||||
insurance 鈥?the model only generates if its provider is live):
|
||||
insurance — the model only generates if its provider is live):
|
||||
```sh
|
||||
curl -s "$BASE/provider?directory=$DIR" | jq '.connected | index("<current providerID>")'
|
||||
# 鈫?null = provider NOT connected (do NOT launch); 0..n = connected
|
||||
# → null = provider NOT connected (do NOT launch); 0..n = connected
|
||||
```
|
||||
or call the `list-models` tool. Note: model-level availability is only
|
||||
knowable at runtime 鈥?a _configured_ model can still fail (subscription-tier
|
||||
knowable at runtime — a _configured_ model can still fail (subscription-tier
|
||||
or region errors); `GET /config/providers` lists _configured_ models, not
|
||||
usable ones. The safest pre-flight is "provider connected" + reusing the
|
||||
current session's model, which is generating by definition. There is **no
|
||||
@@ -226,9 +226,9 @@ it by whichever path fits your context:
|
||||
|
||||
- A reachable octopus HTTP instance (e.g. `http://127.0.0.1:4096`).
|
||||
- The target directory (passed as `?directory=`). Defaults to the current
|
||||
session's directory for in-session launches 鈥?see the Directory convention
|
||||
session's directory for in-session launches — see the Directory convention
|
||||
above; only specify a different one explicitly when targeting another repo.
|
||||
- A known-good `model` (reuse the current session's 鈥?see above). Model IDs
|
||||
- A known-good `model` (reuse the current session's — see above). Model IDs
|
||||
must match the provider config in `<config-home>/octopus/octopus.jsonc`;
|
||||
credentials live in the octopus account keyring (not env), so an isolated
|
||||
HOME cannot reuse them.
|
||||
@@ -242,27 +242,27 @@ BASE=http://127.0.0.1:4096
|
||||
DIR=/data/octopus
|
||||
```
|
||||
|
||||
### Step 1 鈥?Create the session
|
||||
### Step 1 — Create the session
|
||||
|
||||
```sh
|
||||
SID=$(curl -s -X POST "$BASE/session?directory=$DIR" \
|
||||
-H 'content-type: application/json' \
|
||||
-d '{"title":"#N 鈥?<short description>","agent":"builder"}' | jq -r .id)
|
||||
-d '{"title":"#N — <short description>","agent":"builder"}' | jq -r .id)
|
||||
echo "session=$SID"
|
||||
```
|
||||
|
||||
- `POST /session` returns `Session.Info` with `.id` (`groups/session.ts:207-211`).
|
||||
- `?directory=` points at the repo root. For in-session launches it defaults to
|
||||
the **current session's directory** (Directory convention above) 鈥?keep it
|
||||
the **current session's directory** (Directory convention above) — keep it
|
||||
that way so the new session stays visible in the creator's sidebar; pass an
|
||||
explicit path only when targeting a different repo (a worktree of the same
|
||||
repo is NOT a directory target 鈥?hand it over via the seed prompt), and
|
||||
repo is NOT a directory target — hand it over via the seed prompt), and
|
||||
always pass it from cron / CI where no current session exists (server falls
|
||||
back to its own `process.cwd()` otherwise).
|
||||
- `agent` is `builder` (the main agent). Sub-agents (explorer/worker) are
|
||||
spawned within a session 鈥?never named here.
|
||||
spawned within a session — never named here.
|
||||
|
||||
### Step 2 鈥?Deliver the seed prompt (CRITICAL: include a known-good `model`)
|
||||
### Step 2 — Deliver the seed prompt (CRITICAL: include a known-good `model`)
|
||||
|
||||
```sh
|
||||
curl -s -X POST "$BASE/session/$SID/prompt_async?directory=$DIR" \
|
||||
@@ -278,35 +278,35 @@ curl -s -X POST "$BASE/session/$SID/prompt_async?directory=$DIR" \
|
||||
body** when processing starts now (idle session, live runner, noReply
|
||||
injection, or waiting-question preemption), **202** when the message is
|
||||
queued behind a session that is generating with no live runner in this
|
||||
process (wedge/zombie shape 鈥?stored and re-driven on restart drain or the
|
||||
process (wedge/zombie shape — stored and re-driven on restart drain or the
|
||||
next runner), **202** when `delay_sec` defers delivery to an in-memory
|
||||
delayed wake ([org-internal #3937] A 鈥?see "宸℃妯″紡 / Patrol mode" below), and **409**
|
||||
delayed wake ([TT-3937] A — see "巡检模式 / Patrol mode" below), and **409**
|
||||
when the session is paused (message NOT stored) or the maintenance-mode
|
||||
hold queue is full.
|
||||
- **Global route alternative ([org-internal #4307]):** when the client only knows the
|
||||
- **Global route alternative ([TT-4307]):** when the client only knows the
|
||||
sessionID (no `?directory=` routing), `POST /prompt_async` (no path prefix)
|
||||
resolves the instance from the app database by the body's `sessionID` and
|
||||
delegates to the same delivery core 鈥?same 204/202/409 semantics, same
|
||||
delegates to the same delivery core — same 204/202/409 semantics, same
|
||||
`delay_sec` contract, body is the session-scoped payload plus a required
|
||||
`sessionID` field. Unknown sessionID 鈫?404 naming the session-scoped
|
||||
`sessionID` field. Unknown sessionID → 404 naming the session-scoped
|
||||
route. This is the natural fit for the completion-report POST (fixed port,
|
||||
no directory context).
|
||||
- `delay_sec` (optional, integer 0..86400, else 400) schedules the prompt for
|
||||
a one-shot delayed self-wake: the server holds the prompt in memory and
|
||||
fires it exactly once after `delay_sec` seconds, only for an idle session
|
||||
at intake. **Precedence ([org-internal #3937] review):** `delay_sec` applies only when the
|
||||
at intake. **Precedence ([TT-3937] review):** `delay_sec` applies only when the
|
||||
intake would otherwise start processing now (immediate class). For the
|
||||
queued-behind-wedge 202 member and under maintenance queue mode it is
|
||||
stripped 鈥?retention semantics win (the server logs the drop; the delay is
|
||||
NOT honored). Pending wakes are **in-memory only 鈥?a server restart abandons
|
||||
stripped — retention semantics win (the server logs the drop; the delay is
|
||||
NOT honored). Pending wakes are **in-memory only — a server restart abandons
|
||||
them**; a patrol loop must therefore tolerate a missed wake and re-arm.
|
||||
Never use `sleep <big>; curl ...` in a bash tool call to wait 鈥?that blocks
|
||||
the turn with zero output (the [org-internal #3937] incident shape); the bash tool now
|
||||
warns on bare sleeps > 120s (long-sleep guard, [org-internal #3937] C).
|
||||
Never use `sleep <big>; curl ...` in a bash tool call to wait — that blocks
|
||||
the turn with zero output (the [TT-3937] incident shape); the bash tool now
|
||||
warns on bare sleeps > 120s (long-sleep guard, [TT-3937] C).
|
||||
- `model` is `{ providerID, modelID }` or the shorthand string
|
||||
`"providerID/modelID"` (split on the FIRST `/`; accepted since [org-internal #4307] 鈥?
|
||||
`"providerID/modelID"` (split on the FIRST `/`; accepted since [TT-4307] —
|
||||
e.g. `"zai-coding-plan/glm-5.2"`). **Do not omit it.** Fill the values from
|
||||
your own session's model (see "Reuse the current session's model" above) 鈥?
|
||||
your own session's model (see "Reuse the current session's model" above) —
|
||||
never hardcode a specific model. A string without a `/` is rejected with
|
||||
400 naming both accepted forms.
|
||||
- When the seed prompt contains newlines/quotes, build the payload from a file
|
||||
@@ -315,90 +315,90 @@ curl -s -X POST "$BASE/session/$SID/prompt_async?directory=$DIR" \
|
||||
jq -n --rawfile p seed.txt '{agent:"builder",model:{providerID:"<current providerID>",modelID:"<current modelID>"},parts:[{type:"text",text:$p}]}'
|
||||
```
|
||||
|
||||
### Step 3 鈥?Verify the session actually generated (do NOT assume success)
|
||||
### Step 3 — Verify the session actually generated (do NOT assume success)
|
||||
|
||||
HTTP 204/202 鈮?generation success. Poll until an `assistant` message appears. The
|
||||
endpoint is **`/session/:id/message` 鈥?SINGULAR**, and it returns a bare array
|
||||
HTTP 204/202 ≠generation success. Poll until an `assistant` message appears. The
|
||||
endpoint is **`/session/:id/message` — SINGULAR**, and it returns a bare array
|
||||
whose elements are `{ info, parts }` with `role` at `.info.role`
|
||||
(`groups/session.ts:88,183-194`). Poll the **tail with `limit=1`** 鈥?the
|
||||
no-`limit` form loads the ENTIRE transcript server-side (O(messages脳parts) per
|
||||
(`groups/session.ts:88,183-194`). Poll the **tail with `limit=1`** — the
|
||||
no-`limit` form loads the ENTIRE transcript server-side (O(messages×parts) per
|
||||
poll; pitfall #14's 478-message session paid it on every health check), while
|
||||
`limit=1` returns just the newest message (REQ-F-010 windowing, `message.ts`
|
||||
`page()`):
|
||||
|
||||
```sh
|
||||
# wait 5鈥?0s, then poll the TAIL 鈥?never the full transcript
|
||||
# wait 5–10s, then poll the TAIL — never the full transcript
|
||||
curl -s "$BASE/session/$SID/message?directory=$DIR&limit=1" \
|
||||
| jq '{latest_role: .[0].info.role, latest_id: .[0].info.id}'
|
||||
```
|
||||
|
||||
Verdict: `latest_role == "assistant"` 鈫?the first generation completed (the
|
||||
Verdict: `latest_role == "assistant"` → the first generation completed (the
|
||||
seed is `user`; the newest message flips to `assistant` only once the model
|
||||
answered 鈥?an errored turn also persists an assistant message carrying the 鈿狅笍
|
||||
usage-limit part, [org-internal #2912], so check the tail text before declaring success).
|
||||
Stays `user` across 2鈥? polls spaced 10鈥?0 s 鈫?**apparent silent stall**;
|
||||
answered — an errored turn also persists an assistant message carrying the ⚠️
|
||||
usage-limit part, [TT-2912], so check the tail text before declaring success).
|
||||
Stays `user` across 2–3 polls spaced 10–30 s → **apparent silent stall**;
|
||||
almost certainly the model did not resolve to a usable one (fallback landed
|
||||
badly, or you omitted `model`). Redeliver Step 2 with an explicit known-good
|
||||
`model`. Need everything newer than a known point? Page forward with
|
||||
`after=<cursor>&limit=N` and follow the `X-Next-Cursor` response header 鈥?
|
||||
`after=<cursor>&limit=N` and follow the `X-Next-Cursor` response header —
|
||||
just never omit `limit`.
|
||||
|
||||
> 鈿狅笍 Do NOT write `/messages` (plural) 鈥?that path does not exist for listing.
|
||||
> ⚠️ Do NOT write `/messages` (plural) — that path does not exist for listing.
|
||||
> (`POST /session/:id/message`, same singular path but POST, is the synchronous
|
||||
> prompt endpoint; don't confuse the two.)
|
||||
|
||||
## Launch a session for a specific ticket (#N)
|
||||
|
||||
The common case: an agent (or cron/CI) spins up a fresh main session to work a
|
||||
tracked issue 鈥?seed prompt composed **from the issue body**, launched on the
|
||||
current session's model. **Step-0 owner check is MANDATORY ([org-internal #1803])**: four data
|
||||
tracked issue — seed prompt composed **from the issue body**, launched on the
|
||||
current session's model. **Step-0 owner check is MANDATORY ([TT-1803])**: four data
|
||||
sources (session-title scan, assignee/claim, open PRs, remote branches); any
|
||||
live claim 鈫?ABORT the launch (`session-scope-guard.md` points here for that
|
||||
pre-step). Full recipe 鈥?owner-check scan script with `X-Total-Count` /
|
||||
`X-Has-More` pagination handling ([org-internal #3190]), claim-first atomic 3-step ([org-internal #2297],
|
||||
+ one-command provisioning via `script/claim-provision.sh`, [org-internal #3642]),
|
||||
seed-prompt MUSTs, backend duplicate-ticket hard guard ([org-internal #1989], on by default
|
||||
[org-internal #2350]), launch + poll commands: `reference/ticket-recipe.md` (read BEFORE
|
||||
live claim → ABORT the launch (`session-scope-guard.md` points here for that
|
||||
pre-step). Full recipe — owner-check scan script with `X-Total-Count` /
|
||||
`X-Has-More` pagination handling ([TT-3190]), claim-first atomic 3-step ([TT-2297],
|
||||
+ one-command provisioning via `script/claim-provision.sh`, [TT-3642]),
|
||||
seed-prompt MUSTs, backend duplicate-ticket hard guard ([TT-1989], on by default
|
||||
[TT-2350]), launch + poll commands: `reference/ticket-recipe.md` (read BEFORE
|
||||
creating any ticket-driven session).
|
||||
|
||||
## Completion-report protocol (瀹屾垚鍥炴姤鍗忚, [org-internal #2374])
|
||||
## Completion-report protocol (完成回报协议, [TT-2374])
|
||||
|
||||
`prompt_async` is fire-and-forget **for the launcher too**: without this
|
||||
protocol the orchestrator has NO push channel and must poll forever ([org-internal #2366]).
|
||||
protocol the orchestrator has NO push channel and must poll forever ([TT-2366]).
|
||||
The worker actively reports `status=done|blocked|handoff` back into the
|
||||
orchestrator's session via `prompt_async`, with an issue-comment fallback.
|
||||
Default report format is `branch=<ref>`-based 鈥?workers never open PRs
|
||||
(TD-678/[org-internal #4425]); `pr=#N` appears only on `uncoordinated` self-opens.
|
||||
Default report format is `branch=<ref>`-based — workers never open PRs
|
||||
(TD-678/[TT-4425]); `pr=#N` appears only on `uncoordinated` self-opens.
|
||||
Hard constraints: a headless worker MUST NOT call the `question` tool
|
||||
([org-internal #2378] 鈥?directional/irreversible decisions are `status=blocked` reports,
|
||||
([TT-2378] — directional/irreversible decisions are `status=blocked` reports,
|
||||
then STOP), and MUST NOT self-merge its PR / self-close the issue / touch
|
||||
`main` ([org-internal #2386] 鈥?keep the PR open; the orchestrator merges and closes). Full
|
||||
protocol 鈥?orchestrator-side seed block (verbatim template), worker-side
|
||||
`main` ([TT-2386] — keep the PR open; the orchestrator merges and closes). Full
|
||||
protocol — orchestrator-side seed block (verbatim template), worker-side
|
||||
steps, decision-authority layering: `reference/completion-report.md` (read
|
||||
BEFORE composing a seed prompt for any worker you need to hear back from).
|
||||
|
||||
## Post-launch lifecycle: health check, hung rescue, stale-worldview correction ([org-internal #2459])
|
||||
## Post-launch lifecycle: health check, hung rescue, stale-worldview correction ([TT-2459])
|
||||
|
||||
Launching is half the job 鈥?a headless worker can hang silently or wake with
|
||||
a stale worldview. Health check = two polls 30鈥?0 s apart (`.state` + `progress`
|
||||
Launching is half the job — a headless worker can hang silently or wake with
|
||||
a stale worldview. Health check = two polls 30–60 s apart (`.state` + `progress`
|
||||
+ message count); `state=generating` with ALL counters frozen across BOTH
|
||||
samples = hung 鈫?abort FIRST (`POST /session/:id/abort`), then re-wake with a
|
||||
known-good model + the anti-re-hang clause. Stale worldview 鈫?fact-baseline
|
||||
samples = hung → abort FIRST (`POST /session/:id/abort`), then re-wake with a
|
||||
known-good model + the anti-re-hang clause. Stale worldview → fact-baseline
|
||||
injection (only the CURRENT authority injects; if YOU might be the stale one,
|
||||
verify identity against the durable record first). Full runbooks 鈥?verdict
|
||||
table + [org-internal #3215] dual-sample rule, abort + re-wake sequence, fact-baseline
|
||||
verify identity against the durable record first). Full runbooks — verdict
|
||||
table + [TT-3215] dual-sample rule, abort + re-wake sequence, fact-baseline
|
||||
structure, authorization asymmetry: `reference/lifecycle-ops.md` (read when
|
||||
managing a launched session). Quota wall 鈥?the worker's turn killed by a
|
||||
managing a launched session). Quota wall — the worker's turn killed by a
|
||||
terminal usage-limit error (looks like silent completion: no report, ticket
|
||||
stalled) 鈥?has its own runbook: detection signals (finish=error 鈿狅笍 tail,
|
||||
stalled) — has its own runbook: detection signals (finish=error ⚠️ tail,
|
||||
provider quota markers), provider-switch re-wake, fact-baseline template,
|
||||
pre-dispatch provider check: `reference/quota-wall-recovery.md` ([org-internal #3669], evidence
|
||||
[org-internal #3627]; read when a worker goes silent mid-task).
|
||||
pre-dispatch provider check: `reference/quota-wall-recovery.md` ([TT-3669], evidence
|
||||
[TT-3627]; read when a worker goes silent mid-task).
|
||||
|
||||
## 宸℃妯″紡 / Patrol mode (delayed self-wake, [org-internal #3937])
|
||||
## 巡检模式 / Patrol mode (delayed self-wake, [TT-3937])
|
||||
|
||||
A patrol loop periodically nudges a headless session without holding a
|
||||
connection or burning a turn on a blocking sleep. Since [org-internal #3937] A the server
|
||||
connection or burning a turn on a blocking sleep. Since [TT-3937] A the server
|
||||
supports this natively via `delay_sec` on `prompt_async`.
|
||||
|
||||
```sh
|
||||
@@ -414,103 +414,103 @@ curl -s -X POST "$BASE/session/$SID/prompt_async?directory=$DIR" \
|
||||
|
||||
Rules of the road:
|
||||
|
||||
- **202 + `delay_sec` 鈮?queued-behind-wedge 202.** Both are 202, but the
|
||||
- **202 + `delay_sec` ≠queued-behind-wedge 202.** Both are 202, but the
|
||||
delayed wake holds the prompt in memory and delivers it exactly once when
|
||||
the delay elapses (session must have been idle at intake; `0` equals
|
||||
omission 鈫?immediate 204 path). If the session was NOT idle at intake, the
|
||||
omission → immediate 204 path). If the session was NOT idle at intake, the
|
||||
intake keeps the queued semantics and `delay_sec` is ignored (logged
|
||||
server-side) 鈥?the same precedence as maintenance queue mode, where the
|
||||
server-side) — the same precedence as maintenance queue mode, where the
|
||||
intake is retained and `delay_sec` never delays the flush.
|
||||
- **Paused at wake 鈫?dropped, not stored.** The wake's `prompt()` rejects and
|
||||
- **Paused at wake → dropped, not stored.** The wake's `prompt()` rejects and
|
||||
the server publishes an error event; the message is never stored. A patrol
|
||||
driver should check session state before assuming delivery.
|
||||
- **Restart abandons pending wakes.** They are in-memory server fibers 鈥?no
|
||||
- **Restart abandons pending wakes.** They are in-memory server fibers — no
|
||||
persistence, no drain. After any server restart the patrol driver owns
|
||||
re-arming the next wake; treat a missed wake as expected, not as an error.
|
||||
- **Latest wake wins, per session ([org-internal #4069]).** Arming `delay_sec` on a session
|
||||
- **Latest wake wins, per session ([TT-4069]).** Arming `delay_sec` on a session
|
||||
that already has a pending wake SUPERSEDES it: the previous countdown is
|
||||
cancelled, only the latest wake fires. Re-arming each turn is the intended
|
||||
patrol pattern 鈥?a superseded wake never delivers its prompt and publishes
|
||||
no error. (Pre-[org-internal #4069] stacks both FIFO 鈥?on old binaries, re-arm only after
|
||||
patrol pattern — a superseded wake never delivers its prompt and publishes
|
||||
no error. (Pre-[TT-4069] stacks both FIFO — on old binaries, re-arm only after
|
||||
the previous wake fired.)
|
||||
- **Never emulate a delay with the bash tool.** `sleep 900; curl ...` blocks
|
||||
the turn with zero output and gets manually aborted as a hang (the [org-internal #3937]
|
||||
the turn with zero output and gets manually aborted as a hang (the [TT-3937]
|
||||
incident). The bash tool now prepends a `<shell_warning>` on bare sleeps
|
||||
beyond 120s ([org-internal #3937] C) 鈥?treat that warning as a redirect to this section.
|
||||
beyond 120s ([TT-3937] C) — treat that warning as a redirect to this section.
|
||||
|
||||
## Do NOT use this skill when
|
||||
|
||||
- A **persistent client** (Web UI / interactive TUI) is attached 鈥?those use the
|
||||
- A **persistent client** (Web UI / interactive TUI) is attached — those use the
|
||||
synchronous `prompt` endpoint (it blocks until generation completes) and send
|
||||
`model` automatically. Using `prompt_async` there gains nothing and loses the
|
||||
in-line response. This includes the rescue runbook: a hung session driven by
|
||||
a persistent client is the client user's to handle (refresh / re-prompt from
|
||||
the UI) 鈥?abort + re-wake targets headless / managed sessions only.
|
||||
- You want the response **inline** in the same HTTP call 鈥?`prompt_async` is
|
||||
the UI) — abort + re-wake targets headless / managed sessions only.
|
||||
- You want the response **inline** in the same HTTP call — `prompt_async` is
|
||||
fire-and-forget; use the synchronous `prompt` endpoint instead.
|
||||
|
||||
## Common pitfalls
|
||||
|
||||
| # | Pitfall | Fix |
|
||||
| --- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| 1 | Omitting `model` / relying on the fallback 鈫?apparent silent stall (most common) | Always send a known-good `model:{providerID,modelID}` 鈥?reuse the current session's |
|
||||
| 2 | Listing endpoint written `/messages` (plural) 鈫?404 | Use `/session/:id/message` (singular); returns a bare array, role at `.info.role` |
|
||||
| 3 | Copying the session record's model verbatim into the payload | Remap field names: session `.model.id` 鈫?payload `modelID` (session uses `id`, payload uses `modelID`) |
|
||||
| 1 | Omitting `model` / relying on the fallback → apparent silent stall (most common) | Always send a known-good `model:{providerID,modelID}` — reuse the current session's |
|
||||
| 2 | Listing endpoint written `/messages` (plural) → 404 | Use `/session/:id/message` (singular); returns a bare array, role at `.info.role` |
|
||||
| 3 | Copying the session record's model verbatim into the payload | Remap field names: session `.model.id` → payload `modelID` (session uses `id`, payload uses `modelID`) |
|
||||
| 4 | Stale `octopus` binary rejects newer config schema (`Unrecognized key`) | Use the source CLI `bun run ./src/index.ts ...`; the config itself is valid |
|
||||
| 5 | Missing `?directory=` query param | In-session launch: default to the current session's directory. Cron/CI (no current session): pass the repo root explicitly 鈥?server falls back to its own `process.cwd()` |
|
||||
| 6 | Using synchronous `prompt` for headless launch | `prompt` blocks until done 鈥?wrong for fire-and-forget; use `prompt_async` |
|
||||
| 5 | Missing `?directory=` query param | In-session launch: default to the current session's directory. Cron/CI (no current session): pass the repo root explicitly — server falls back to its own `process.cwd()` |
|
||||
| 6 | Using synchronous `prompt` for headless launch | `prompt` blocks until done — wrong for fire-and-forget; use `prompt_async` |
|
||||
| 7 | Shell-escaping errors in a multi-line seed prompt | Build the payload with `jq -n --rawfile` from a file |
|
||||
| 8 | Verifying models via `GET /model` 鈥?no such endpoint (404) | Use `GET /provider` 鈫?`.connected` (provider live check); `list-models` tool also works. `GET /config/providers` lists _configured_ models only |
|
||||
| 9 | Launching a session for a ticket another live session already owns 鈫?conflicting diffs, duplicate work ([org-internal #1744]/[org-internal #1753]) | Run the Step-0 owner check (`GET /session` title scan + worktree/branch/PR scan); ABORT and report on conflict |
|
||||
| 10 | Creating a worktree / fresh checkout for the new session (unnecessary `bun install` + `.codegraph/` rebuild cost) | Don't 鈥?for _general_ launches: a session is a conversation pointed at a directory, so reuse the current workspace; worktree creation is a separate _workflow_ decision the launched session makes if/when it starts a workflow. **Ticket-recipe carve-out ([org-internal #2297]):** the ticket's work happens in a dedicated worktree anyway (worktree discipline), and claim-first pushes the workflow branch before launch 鈥?so the launcher pre-builds the worktree as the claim carrier + ready workspace, and the session reuses it (cost is front-loaded, not wasted). The worktree path goes in the claim comment + seed prompt; `?directory=` stays on the creator's workspace |
|
||||
| 11 | Launching a worker and never hearing back 鈥?orchestrator polls a few times, stops, loses visibility ([org-internal #2374]) | Append the completion-report block to the seed prompt (Completion-report protocol section): worker `prompt_async`s a one-line status back into the orchestrator session on done/blocked/handoff, with issue-comment fallback |
|
||||
| 12 | Headless worker calls the `question` tool 鈫?no attached client: the question deadlocks in a queue, or `auto_approve` silently auto-approves a direction-setting decision ([org-internal #2378]) | NEVER call `question` from a headless worker. Decision boundary (Completion-report protocol section): directional/irreversible decision 鈫?`status=blocked` report + one-line decision point, then STOP; the orchestrator is the sole human-decision entry point |
|
||||
| 13 | Headless worker self-merges its PR / self-closes the issue once the PR looks ready, despite a seed instruction to keep it open ([org-internal #2386]; N-02 [org-internal #2367] / N-03 [org-internal #2368], commits `d1565c99` / `040f21b7`) | Self-merge / self-close / touching `main` are irreversible directional actions 鈫?blocked by the Decision boundary. PR ready 鈫?keep it OPEN, report `status=done branch=<ref>`; the orchestrator opens/admits the PR, merges and closes uniformly |
|
||||
| 14 | Trusting `state=generating` as "alive" 鈥?a hung stream goes unrescued (session A, 2026-08-16: `generating` 6+ min, count frozen at 478) | Poll state AND message count twice 30鈥?0 s apart; frozen count = hung 鈫?abort + re-wake (Post-launch lifecycle section) |
|
||||
| 15 | Re-sending a wake prompt to a hung session and waiting 鈥?queued prompts are never consumed while the stream is dead | Abort FIRST (`POST /session/:id/abort` 鈫?200, verify `idle`), THEN re-send; a prompt queued before the abort may still never fire 鈥?always re-deliver |
|
||||
| 16 | A worker woken from restart / long idle acts on its stale worldview 鈥?re-dispatches superseded work or claims authority it no longer holds (2026-08-16: revived worker re-ran an already-published FAIL verify; ops session announced an inherited "orchestrator" takeover) | Fact-baseline injection (Post-launch lifecycle section): authoritative facts + invalidated assumptions + one concrete re-assignment. Only the CURRENT authority injects; a session that suspects IT is stale verifies identity against the durable record first (`rules/compact.md` identity clause) |
|
||||
| 17 | Worker goes silent mid-task: provider quota wall killed the turn (usage limit / 429) 鈥?no completion-report, no blocked report; from the issue side indistinguishable from silent completion (2026-08-29 [org-internal #3627]: opencode-go `weekly usage limit reached` after the 13:18 Round-1 FAIL; ticket stalled until manually re-woken) | Detect via tail probe (`finish=error` + 鈿狅笍 usage-limit part, `metadata.reason` in the quota family) + `GET /provider` quota markers; re-wake on a known-good provider with the fact-baseline template 鈥?`reference/quota-wall-recovery.md` ([org-internal #3669]). Prevent: pre-dispatch provider check + the seed's 閰嶉鑷姤 clause (`reference/completion-report.md`, [org-internal #3669]) 鈥?quota exhaustion is a `status=blocked reason=quota-exhausted` report, not a silent death |
|
||||
| 8 | Verifying models via `GET /model` — no such endpoint (404) | Use `GET /provider` → `.connected` (provider live check); `list-models` tool also works. `GET /config/providers` lists _configured_ models only |
|
||||
| 9 | Launching a session for a ticket another live session already owns → conflicting diffs, duplicate work ([TT-1744]/[TT-1753]) | Run the Step-0 owner check (`GET /session` title scan + worktree/branch/PR scan); ABORT and report on conflict |
|
||||
| 10 | Creating a worktree / fresh checkout for the new session (unnecessary `bun install` + `.codegraph/` rebuild cost) | Don't — for _general_ launches: a session is a conversation pointed at a directory, so reuse the current workspace; worktree creation is a separate _workflow_ decision the launched session makes if/when it starts a workflow. **Ticket-recipe carve-out ([TT-2297]):** the ticket's work happens in a dedicated worktree anyway (worktree discipline), and claim-first pushes the workflow branch before launch — so the launcher pre-builds the worktree as the claim carrier + ready workspace, and the session reuses it (cost is front-loaded, not wasted). The worktree path goes in the claim comment + seed prompt; `?directory=` stays on the creator's workspace |
|
||||
| 11 | Launching a worker and never hearing back — orchestrator polls a few times, stops, loses visibility ([TT-2374]) | Append the completion-report block to the seed prompt (Completion-report protocol section): worker `prompt_async`s a one-line status back into the orchestrator session on done/blocked/handoff, with issue-comment fallback |
|
||||
| 12 | Headless worker calls the `question` tool → no attached client: the question deadlocks in a queue, or `auto_approve` silently auto-approves a direction-setting decision ([TT-2378]) | NEVER call `question` from a headless worker. Decision boundary (Completion-report protocol section): directional/irreversible decision → `status=blocked` report + one-line decision point, then STOP; the orchestrator is the sole human-decision entry point |
|
||||
| 13 | Headless worker self-merges its PR / self-closes the issue once the PR looks ready, despite a seed instruction to keep it open ([TT-2386]; N-02 [TT-2367] / N-03 [TT-2368], commits `d1565c99` / `040f21b7`) | Self-merge / self-close / touching `main` are irreversible directional actions → blocked by the Decision boundary. PR ready → keep it OPEN, report `status=done branch=<ref>`; the orchestrator opens/admits the PR, merges and closes uniformly |
|
||||
| 14 | Trusting `state=generating` as "alive" — a hung stream goes unrescued (session A, 2026-08-16: `generating` 6+ min, count frozen at 478) | Poll state AND message count twice 30–60 s apart; frozen count = hung → abort + re-wake (Post-launch lifecycle section) |
|
||||
| 15 | Re-sending a wake prompt to a hung session and waiting — queued prompts are never consumed while the stream is dead | Abort FIRST (`POST /session/:id/abort` → 200, verify `idle`), THEN re-send; a prompt queued before the abort may still never fire — always re-deliver |
|
||||
| 16 | A worker woken from restart / long idle acts on its stale worldview — re-dispatches superseded work or claims authority it no longer holds (2026-08-16: revived worker re-ran an already-published FAIL verify; ops session announced an inherited "orchestrator" takeover) | Fact-baseline injection (Post-launch lifecycle section): authoritative facts + invalidated assumptions + one concrete re-assignment. Only the CURRENT authority injects; a session that suspects IT is stale verifies identity against the durable record first (`rules/compact.md` identity clause) |
|
||||
| 17 | Worker goes silent mid-task: provider quota wall killed the turn (usage limit / 429) — no completion-report, no blocked report; from the issue side indistinguishable from silent completion (2026-08-29 [TT-3627]: opencode-go `weekly usage limit reached` after the 13:18 Round-1 FAIL; ticket stalled until manually re-woken) | Detect via tail probe (`finish=error` + ⚠️ usage-limit part, `metadata.reason` in the quota family) + `GET /provider` quota markers; re-wake on a known-good provider with the fact-baseline template — `reference/quota-wall-recovery.md` ([TT-3669]). Prevent: pre-dispatch provider check + the seed's 配额自报 clause (`reference/completion-report.md`, [TT-3669]) — quota exhaustion is a `status=blocked reason=quota-exhausted` report, not a silent death |
|
||||
|
||||
## Known limitation (separate from this workaround)
|
||||
|
||||
A missing `model` producing an **apparent silent stall** (no surfaced error, no
|
||||
generation) is an observability / robustness gap. Current code does NOT
|
||||
hard-require `model` 鈥?it fills it via a fallback chain (`prompt.ts:858`) and any
|
||||
hard-require `model` — it fills it via a fallback chain (`prompt.ts:858`) and any
|
||||
resolution failure surfaces as a published `Session.Event.Error` on the
|
||||
synchronous path (`prompt.ts:804-822`), but the **async** `prompt_async` handler
|
||||
catches that cause (`forkPromptDelivery` in `handlers/session.ts`) so the HTTP
|
||||
caller never sees it. The proper fix is to surface the error (or reject unusable
|
||||
models at the boundary) so a stalled session is diagnosable. Until then, **always
|
||||
provide an explicit known-good `model`** 鈥?this skill is the documented
|
||||
workaround (see [org-internal #1695] "閬楃暀 minor").
|
||||
provide an explicit known-good `model`** — this skill is the documented
|
||||
workaround (see [TT-1695] "遗留 minor").
|
||||
|
||||
**Update ([org-internal #2912], 2026-08-20)**: usage-limit turn failures (HTTP 429 /
|
||||
**Update ([TT-2912], 2026-08-20)**: usage-limit turn failures (HTTP 429 /
|
||||
FreeUsageLimitError / GoUsageLimitError) are no longer silent shells. When such
|
||||
a turn terminates (retry schedule ends or the spin is aborted), the errored
|
||||
assistant message persists `finish=error` plus a human-readable 鈿狅笍 text part
|
||||
assistant message persists `finish=error` plus a human-readable ⚠️ text part
|
||||
carrying provider, limit reason, and reset hint (`metadata: { error: true,
|
||||
reason, provider }`) 鈥?visible via `GET /session/:id/message` and rendered in
|
||||
reason, provider }`) — visible via `GET /session/:id/message` and rendered in
|
||||
the web UI like any assistant text. Pitfall #14's double-poll is still the
|
||||
liveness check while a 429 retry spin is IN progress (the spin itself retries
|
||||
with backoff until interrupted); the explicit error part only appears once the
|
||||
turn ends. The general async-path observability gap above remains tracked by
|
||||
[org-internal #1695].
|
||||
[TT-1695].
|
||||
|
||||
## See also
|
||||
|
||||
- Source issue / full manual: **[org-internal #1695]** (this skill adds the ticket-driven recipe
|
||||
- Source issue / full manual: **[TT-1695]** (this skill adds the ticket-driven recipe
|
||||
- current-model reuse, and corrects the endpoint/claim against current code).
|
||||
- Completion-report protocol: **[org-internal #2374]** (worker-side active report back to the
|
||||
- Completion-report protocol: **[TT-2374]** (worker-side active report back to the
|
||||
launching orchestrator session; fallback to issue comment).
|
||||
- Quota-wall recovery recipe: **[org-internal #3669]** (evidence instance [org-internal #3627]) 鈥?detect a
|
||||
- Quota-wall recovery recipe: **[TT-3669]** (evidence instance [TT-3627]) — detect a
|
||||
worker killed by a provider usage limit, re-wake on a known-good provider,
|
||||
pre-dispatch prevention.
|
||||
- Decision boundary: **[org-internal #2378]** (headless worker MUST NOT call `question`;
|
||||
- Decision boundary: **[TT-2378]** (headless worker MUST NOT call `question`;
|
||||
directional decisions go through `status=blocked` reports to the
|
||||
orchestrator) and **[org-internal #2386]** (the worker MUST NOT self-merge its PR,
|
||||
self-close the issue, or touch `main` 鈥?the orchestrator merges and closes
|
||||
orchestrator) and **[TT-2386]** (the worker MUST NOT self-merge its PR,
|
||||
self-close the issue, or touch `main` — the orchestrator merges and closes
|
||||
uniformly).
|
||||
- Correction of the prior misdiagnosis: **[org-internal #1691]** (closed Invalid), comment 9205.
|
||||
- Correction of the prior misdiagnosis: **[TT-1691]** (closed Invalid), comment 9205.
|
||||
- Synchronous client always sends `model`:
|
||||
`packages/app/src/components/prompt-input/submit.ts:158-165`.
|
||||
- Code citations: `<harness-package>/src/session/prompt.ts:858,804-822,1399`,
|
||||
@@ -519,29 +519,29 @@ turn ends. The general async-path observability gap above remains tracked by
|
||||
|
||||
## References
|
||||
|
||||
**On-demand references** (NOT injected 鈥?read at the declared timing):
|
||||
**On-demand references** (NOT injected — read at the declared timing):
|
||||
|
||||
- `reference/ticket-recipe.md` 鈥?ticket-driven launch (`Launch a session for a
|
||||
specific ticket (#N)`): read BEFORE creating any session for issue #N 鈥?
|
||||
- `reference/ticket-recipe.md` — ticket-driven launch (`Launch a session for a
|
||||
specific ticket (#N)`): read BEFORE creating any session for issue #N —
|
||||
Step-0 owner check, seed-prompt composition, launch + poll commands.
|
||||
- `reference/completion-report.md` 鈥?completion-report protocol (瀹屾垚鍥炴姤鍗忚,
|
||||
[org-internal #2374]): read BEFORE composing a seed prompt for a worker you need to hear
|
||||
back from 鈥?orchestrator block template, worker-side report steps, decision
|
||||
boundary ([org-internal #2378] / [org-internal #2386]), quota self-report clause ([org-internal #3669]).
|
||||
- `reference/lifecycle-ops.md` 鈥?post-launch lifecycle ([org-internal #2459]): read when
|
||||
managing a launched session 鈥?health-check polling, hung-stream diagnosis
|
||||
- `reference/completion-report.md` — completion-report protocol (完成回报协议,
|
||||
[TT-2374]): read BEFORE composing a seed prompt for a worker you need to hear
|
||||
back from — orchestrator block template, worker-side report steps, decision
|
||||
boundary ([TT-2378] / [TT-2386]), quota self-report clause ([TT-3669]).
|
||||
- `reference/lifecycle-ops.md` — post-launch lifecycle ([TT-2459]): read when
|
||||
managing a launched session — health-check polling, hung-stream diagnosis
|
||||
(state=generating + frozen counters), abort + re-wake rescue,
|
||||
fact-baseline injection, authorization asymmetry.
|
||||
- `reference/quota-wall-recovery.md` 鈥?quota-wall recovery ([org-internal #3669], evidence
|
||||
[org-internal #3627]): read when a worker goes silent mid-task (suspected provider usage
|
||||
limit) or BEFORE dispatching a long-running worker 鈥?detection signals
|
||||
(finish=error 鈿狅笍 tail, provider quota markers, log grep patterns),
|
||||
- `reference/quota-wall-recovery.md` — quota-wall recovery ([TT-3669], evidence
|
||||
[TT-3627]): read when a worker goes silent mid-task (suspected provider usage
|
||||
limit) or BEFORE dispatching a long-running worker — detection signals
|
||||
(finish=error ⚠️ tail, provider quota markers, log grep patterns),
|
||||
provider-switch re-wake + fact-baseline template, pre-dispatch provider
|
||||
check, quota self-report clause.
|
||||
|
||||
- `rules/headless-session-ops` wiki page 鈥?authoritative reference (this
|
||||
- `rules/headless-session-ops` wiki page — authoritative reference (this
|
||||
skill is its runtime carrier; link in the Directory-convention note above).
|
||||
- `core/rules/session-scope-guard.md` 鈥?owner-check + claim-first rule
|
||||
- `core/rules/session-scope-guard.md` — owner-check + claim-first rule
|
||||
(the ticket recipe's Step 0 is its launch-time application).
|
||||
- `core/rules/compact.md` 鈥?identity-verification clause backing the
|
||||
- `core/rules/compact.md` — identity-verification clause backing the
|
||||
authorization-asymmetry rule (`reference/lifecycle-ops.md`).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
> Extracted from headless-session-ops/SKILL.md (Completion-report protocol (完成回报协议, [org-internal #2374])) — moved verbatim 2026-08-26, ticket [org-internal #3480].
|
||||
> Extracted from headless-session-ops/SKILL.md (Completion-report protocol (完成回报协议, [TT-2374])) — moved verbatim 2026-08-26, ticket [TT-3480].
|
||||
|
||||
## Completion-report protocol (完成回报协议, [org-internal #2374])
|
||||
## Completion-report protocol (完成回报协议, [TT-2374])
|
||||
|
||||
`prompt_async` is fire-and-forget **for the launcher too**: once the worker
|
||||
session starts generating, the orchestrator receives NO event when it finishes
|
||||
@@ -8,8 +8,8 @@ or blocks. The `task` tool auto-returns `task_result` for subagents; a
|
||||
`prompt_async`-launched independent main session has no equivalent — the
|
||||
orchestrator's only built-in channel is bare polling of
|
||||
`GET /session/:id/message?limit=1` (tail probe — the no-`limit` form loads the
|
||||
whole transcript server-side), which it eventually stops doing ([org-internal #2366]: worker ran
|
||||
~1h past the orchestrator's last poll, merged PR [org-internal #2371] and closed [org-internal #2366] while
|
||||
whole transcript server-side), which it eventually stops doing ([TT-2366]: worker ran
|
||||
~1h past the orchestrator's last poll, merged PR [TT-2371] and closed [TT-2366] while
|
||||
the orchestrator had zero visibility).
|
||||
|
||||
The protocol below closes that gap WITHOUT changing server semantics: the
|
||||
@@ -24,21 +24,21 @@ parallel chunk work, any long-running delegated ticket), append a
|
||||
completion-report block to the seed prompt. It MUST state:
|
||||
|
||||
- the orchestrator's **session id** (`$LAUNCHER_SID`) and **directory**;
|
||||
- the report endpoint: `POST $BASE/session/$LAUNCHER_SID/prompt_async?directory=$DIR` (or, when the directory is unknown to the worker, the global route `POST $BASE/prompt_async` with the sessionID in the body — [org-internal #4307]);
|
||||
- the report endpoint: `POST $BASE/session/$LAUNCHER_SID/prompt_async?directory=$DIR` (or, when the directory is unknown to the worker, the global route `POST $BASE/prompt_async` with the sessionID in the body — [TT-4307]);
|
||||
- the exact report format (one-line, machine-greppable);
|
||||
- the fallback (issue comment) if the report call fails.
|
||||
|
||||
Template (include verbatim in `seed.txt` when you are the launcher):
|
||||
|
||||
```text
|
||||
## 完成回报协议 (mandatory, [org-internal #2374])
|
||||
## 完成回报协议 (mandatory, [TT-2374])
|
||||
|
||||
你由编排会话 (orchestrator) 启动。完成、阻塞、或将工单移交他人时,必须向编排会话回报:
|
||||
POST <BASE>/session/<LAUNCHER_SID>/prompt_async?directory=<DIR>
|
||||
body: {"agent":"builder","model":{...},"parts":[{"type":"text","text":"<report>"}]}
|
||||
<report> 格式(单行,machine-greppable):
|
||||
[#<ticket>] [<node-or-slug>] status=done|blocked|handoff branch=<ref> [pr=#<N>] verify=<changed+typecheck> risk=<high|low> summary=<one line>
|
||||
默认(TD-678 / [org-internal #4425]):worker 只推分支不开 PR——交付推送前置本地验证
|
||||
默认(TD-678 / [TT-4425]):worker 只推分支不开 PR——交付推送前置本地验证
|
||||
(<harness-package> 下 test:changed 全绿 + typecheck 0 error,verify 字段回执);
|
||||
risk 按 risk-classifier 冻结表(HIGH_RISK_GLOBS)自报。PR 由编排按容量串行开
|
||||
1:1(正文携 worker 报告),或 batch 模式 epic 经 land-batch 技能按迭代统一合成
|
||||
@@ -46,15 +46,15 @@ risk 按 risk-classifier 冻结表(HIGH_RISK_GLOBS)自报。PR 由编排按
|
||||
若回报调用失败(HTTP 非 2xx / 连接拒绝 — orchestrator 会话可能已结束或实例重启),
|
||||
退而在源 issue(或父 Epic)发同内容评论作为兜底(fallback, 非主通道)。
|
||||
回报是你的 mandatory step,与 issue-checklist-sync 并列;不得静默结束。
|
||||
决策边界([org-internal #2378]):headless worker 禁止调用 `question` 工具 —— 遇方向性/不可逆
|
||||
决策边界([TT-2378]):headless worker 禁止调用 `question` 工具 —— 遇方向性/不可逆
|
||||
决策点 → `status=blocked` + 一行决策点描述后 STOP,勿调 question(无人应答死锁 /
|
||||
被 auto_approve 静默自动批准)。
|
||||
配额自报([org-internal #3669]):若收到配额/用量上限错误(usage limit / 429 / 402
|
||||
配额自报([TT-3669]):若收到配额/用量上限错误(usage limit / 429 / 402
|
||||
insufficient_quota),立即回报 status=blocked reason=quota-exhausted
|
||||
summary=<provider 与 ⚠️ 部分中的重置提示>(branch=<ref> 必带)后停止
|
||||
——勿自行换模型重试;换供应商重唤醒由编排者执行
|
||||
(reference/quota-wall-recovery.md)。
|
||||
PR 就绪后保持 open:不自行合并 PR、不关闭 issue、不动 main([org-internal #2386]);
|
||||
PR 就绪后保持 open:不自行合并 PR、不关闭 issue、不动 main([TT-2386]);
|
||||
合并与 issue 关闭由编排者统一执行。
|
||||
```
|
||||
|
||||
@@ -73,7 +73,7 @@ final step (before idling):
|
||||
done); `pr=#N` only for an `uncoordinated` self-open; use
|
||||
`status=blocked` + the blocker description when stuck; use
|
||||
`status=handoff` when deliberately transferring the ticket.
|
||||
1. **Quota exhaustion is a blocked report, not a silent death ([org-internal #3669]).** A
|
||||
1. **Quota exhaustion is a blocked report, not a silent death ([TT-3669]).** A
|
||||
worker whose turn is killed by a usage-limit error (429 / 402 quota
|
||||
family) cannot finish the turn — but per the seed's 配额自报 clause it
|
||||
reports `status=blocked reason=quota-exhausted summary=<provider +
|
||||
@@ -93,7 +93,7 @@ final step (before idling):
|
||||
remains the stakeholder-facing record; the report is the
|
||||
orchestrator-facing wake-up signal.
|
||||
|
||||
### Orchestrator side — serial PR admission on done reports ([org-internal #4425])
|
||||
### Orchestrator side — serial PR admission on done reports ([TT-4425])
|
||||
|
||||
On a `status=done branch=<ref> verify=… risk=…` report:
|
||||
|
||||
@@ -103,16 +103,16 @@ On a `status=done branch=<ref> verify=… risk=…` report:
|
||||
code; keep the queue shallow.
|
||||
2. Open the 1:1 PR (title from the ticket node, body carrying the worker
|
||||
report: branch / files / self-test / verify), apply the `Risk/*` label
|
||||
from the report's `risk=` hint, merge via `script/pr-merge.sh` ([org-internal #3864]).
|
||||
Batch-mode epics: one `land-batch` PR per iteration instead ([org-internal #3731]).
|
||||
from the report's `risk=` hint, merge via `script/pr-merge.sh` ([TT-3864]).
|
||||
Batch-mode epics: one `land-batch` PR per iteration instead ([TT-3731]).
|
||||
3. A first red on the opened PR goes back through the report fallback
|
||||
channel (issue comment) — the worker may already be idle; the issue
|
||||
comment is the durable re-entry point.
|
||||
|
||||
Prose discipline on the orchestrator session only — no new daemon, no
|
||||
mergeable-state automation (merge-coordinator retired, [org-internal #4385]).
|
||||
mergeable-state automation (merge-coordinator retired, [TT-4385]).
|
||||
|
||||
### Decision boundary (决策边界, [org-internal #2378])
|
||||
### Decision boundary (决策边界, [TT-2378])
|
||||
|
||||
The report channel defines how the worker *answers*; this subsection defines
|
||||
the boundary of what it may *ask*. A headless worker session has NO attached
|
||||
@@ -134,15 +134,15 @@ authority is layered instead:
|
||||
point, then STOPs. The orchestrator is the sole human-decision entry point:
|
||||
it interacts with the user, then replies to the worker (or acts on its
|
||||
behalf).
|
||||
- **No self-merge / no self-close / never touch main ([org-internal #2386])**: a headless
|
||||
- **No self-merge / no self-close / never touch main ([TT-2386])**: a headless
|
||||
worker MUST NOT merge its own PR, close the source issue, or rebase /
|
||||
force-push `main`. These are irreversible directional actions of exactly
|
||||
the class this boundary blocks — even when the seed prompt's instruction
|
||||
to "keep the PR open" is absent or the worker judges the PR ready. When
|
||||
the PR is ready the worker keeps it OPEN and reports
|
||||
`status=done pr=#N` to the orchestrator; the orchestrator performs the
|
||||
merge and the issue close uniformly. (Counter-example: N-02 [org-internal #2367] /
|
||||
N-03 [org-internal #2368] self-merged their PRs — commits `d1565c99` / `040f21b7` —
|
||||
merge and the issue close uniformly. (Counter-example: N-02 [TT-2367] /
|
||||
N-03 [TT-2368] self-merged their PRs — commits `d1565c99` / `040f21b7` —
|
||||
despite a seed instruction to keep them open.)
|
||||
- **Local implementation decisions within the AC scope** (pattern choice,
|
||||
helper extraction, test shape) → the worker decides autonomously and notes
|
||||
@@ -150,7 +150,7 @@ authority is layered instead:
|
||||
|
||||
Rule of thumb: the worker's only way to "ask" is a `status=blocked` report.
|
||||
A genuine ambiguity left by the seed prompt that would change scope is a
|
||||
blocked report, NOT a `question` call. (Field sample: N-04 [org-internal #2369] — the
|
||||
blocked report, NOT a `question` call. (Field sample: N-04 [TT-2369] — the
|
||||
worker spontaneously did NOT merge its own PR and left merging to the
|
||||
orchestrator; this subsection codifies that behavior.)
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
> Extracted from headless-session-ops/SKILL.md (Post-launch lifecycle: health check, hung rescue, stale-worldview correction ([org-internal #2459])) — moved verbatim 2026-08-26, ticket [org-internal #3480].
|
||||
> Extracted from headless-session-ops/SKILL.md (Post-launch lifecycle: health check, hung rescue, stale-worldview correction ([TT-2459])) — moved verbatim 2026-08-26, ticket [TT-3480].
|
||||
|
||||
## Post-launch lifecycle: health check, hung rescue, stale-worldview correction ([org-internal #2459])
|
||||
## Post-launch lifecycle: health check, hung rescue, stale-worldview correction ([TT-2459])
|
||||
|
||||
Launching is half the job — a headless worker can hang silently or wake up
|
||||
with an outdated worldview. All three failure modes below were observed in
|
||||
production on 2026-08-16 during Epic [org-internal #2459] (ops-restart window); the runbooks
|
||||
production on 2026-08-16 during Epic [TT-2459] (ops-restart window); the runbooks
|
||||
are extracted from that incident record.
|
||||
|
||||
### Health check — three states, one poll pattern
|
||||
@@ -24,7 +24,7 @@ server-side:
|
||||
| idle | `state=idle` AND `progress` absent-or-stale across both polls | turn ended — read the LAST message (same `limit=1` fetch): task unfinished → wake prompt; `status=done` report → harvest |
|
||||
| **hung** | `state=generating` AND `progress.stepCount`/`lastStepAt` AND newest message id ALL frozen across both polls | the generation stream is dead; queued prompts will NEVER be consumed — rescue required |
|
||||
|
||||
`state` alone lies in BOTH directions ([org-internal #3215]): a hung session still reports
|
||||
`state` alone lies in BOTH directions ([TT-3215]): a hung session still reports
|
||||
`generating` (field sample: session A, 2026-08-16 — `state=generating` for 6+
|
||||
minutes with the message count frozen at 478), and a healthy mid-step worker
|
||||
can read `idle`/empty message tails in a single snapshot (2026-08-23 W3 wave:
|
||||
@@ -32,7 +32,7 @@ can read `idle`/empty message tails in a single snapshot (2026-08-23 W3 wave:
|
||||
discriminator; a single snapshot is NEVER an abort basis.**
|
||||
|
||||
`progress` (`stepCount` cumulative LLM-round counter, `lastStepAt` epoch-ms
|
||||
heartbeat — [org-internal #3215]) moves on every round even when message tails are
|
||||
heartbeat — [TT-3215]) moves on every round even when message tails are
|
||||
transiently empty or `state` flickers; it is absent for sessions that never
|
||||
ran since instance start (treat absent = no signal, fall back to count
|
||||
deltas). `lastStepAt` freshness alone does NOT prove liveness (a long tool
|
||||
@@ -77,7 +77,7 @@ claim authority it does not hold (field samples, 2026-08-16: a revived worker
|
||||
re-ran an M-01 verify another session had already published as FAIL —
|
||||
deduplicated via flag #comment-21590; an ops-notification session inherited an
|
||||
"orchestrator" identity from a compaction summary and announced a takeover —
|
||||
corrected via 勘误 #comment-21654/[org-internal #21668]).
|
||||
corrected via 勘误 #comment-21654/[TT-21668]).
|
||||
|
||||
When you detect a stale-worldview session, do not wait for it to finish being
|
||||
wrong — inject a fact-baseline prompt immediately (regular `prompt_async`),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
> Added from headless-session-ops/SKILL.md (triggers `quota wall` / `配额墙`,
|
||||
> Post-launch lifecycle section, pitfall #17, References) — new runbook
|
||||
> 2026-08-29, ticket [org-internal #3669] (evidence instance [org-internal #3627]). Companion runbooks:
|
||||
> 2026-08-29, ticket [TT-3669] (evidence instance [TT-3627]). Companion runbooks:
|
||||
> `lifecycle-ops.md` (hung rescue, fact-baseline structure) and
|
||||
> `completion-report.md` §"Orchestrator side" (the quota self-report clause);
|
||||
> §Prevention is this file's own closing section.
|
||||
@@ -14,15 +14,15 @@ it looks EXACTLY like silent completion: no completion-report, no
|
||||
equals the orchestrator's polling interval, and without this runbook the
|
||||
recovery was improvised.
|
||||
|
||||
**Evidence instance ([org-internal #3627], 2026-08-29)** — the shapes below are field-verified:
|
||||
**Evidence instance ([TT-3627], 2026-08-29)** — the shapes below are field-verified:
|
||||
|
||||
|时刻 (+08)| 事件 |
|
||||
|---|---|
|
||||
| 08-29 13:18 | review-code Round-1 synthesis (FAIL) posted on [org-internal #3627]; worker session `ses_fb46e705bffe9kYbSoHayoJ1OQ` (builder, opencode-go model, branch `workflow/session/3627-wedge-promptasync`) entered its revision loop |
|
||||
| 08-29 13:18 | review-code Round-1 synthesis (FAIL) posted on [TT-3627]; worker session `ses_fb46e705bffe9kYbSoHayoJ1OQ` (builder, opencode-go model, branch `workflow/session/3627-wedge-promptasync`) entered its revision loop |
|
||||
| ~13:18–16:00 | worker hit the provider's `weekly usage limit reached` mid-revision — turn killed, **no** completion-report, **no** blocked report; issue side silent |
|
||||
| detection | orchestrator noticed the `/session` state stall, then confirmed via the quota error in the session log (message tail carries the ⚠️ usage-limit part, [org-internal #2912]) |
|
||||
| detection | orchestrator noticed the `/session` state stall, then confirmed via the quota error in the session log (message tail carries the ⚠️ usage-limit part, [TT-2912]) |
|
||||
| recovery | re-wake via `prompt_async` on a known-good provider (`zhipuai-coding-plan`/glm-5.3 — since renamed `zai-coding-plan`) **plus a fact-baseline injection** (what happened / what is done / where to resume) |
|
||||
| 16:26 / 16:51 | Round-2 synthesis PASS; `status=done pr=[org-internal #3675]` report received |
|
||||
| 16:26 / 16:51 | Round-2 synthesis PASS; `status=done pr=[TT-3675]` report received |
|
||||
|
||||
## Detection — three signals, in this order
|
||||
|
||||
@@ -35,7 +35,7 @@ SID=<worker session id>
|
||||
```
|
||||
|
||||
**Signal 1 — tail probe (primary; survives restarts, lives in the DB).** Since
|
||||
[org-internal #2912]/[org-internal #3190] a quota-killed turn persists an assistant message with
|
||||
[TT-2912]/[TT-3190] a quota-killed turn persists an assistant message with
|
||||
`finish=error` plus a human-readable ⚠️ text part whose metadata names the
|
||||
quota family. Probe the TAIL (`limit=1`, never the no-`limit` full transcript):
|
||||
|
||||
@@ -52,10 +52,10 @@ rate_limit}` (metadata also carries `provider`). The ⚠️ text is one of — a
|
||||
strings observed in this repo's runtime (`session/retry.ts`):
|
||||
|
||||
- `` `weekly usage limit` reached. It will reset in … `` / `Go limit reached`
|
||||
(GoUsageLimitError — the [org-internal #3627] shape; `weekly` is the body's `limitName`)
|
||||
(GoUsageLimitError — the [TT-3627] shape; `weekly` is the body's `limitName`)
|
||||
- `Free limit reached` (FreeUsageLimitError)
|
||||
- `Account-level usage limit — switching API keys does not reset it. You can
|
||||
continue after HH:mm.` ([org-internal #3407], zhipu/zai code 1308 — account-level)
|
||||
continue after HH:mm.` ([TT-3407], zhipu/zai code 1308 — account-level)
|
||||
- `Provider <id> rate limited (HTTP 429)` (generic 429)
|
||||
- `Generation failed — …` with a 402 `insufficient_quota` body (balance, not
|
||||
window — recovery is top-up, not provider switch)
|
||||
@@ -73,9 +73,9 @@ curl -s "$BASE/session?directory=$DIR" | jq -r --arg s "$SID" \
|
||||
30–60 s apart → the 429 retry spin is still running (it retries with backoff
|
||||
until the schedule ends) OR the stream is hung — treat exactly like the hung
|
||||
shape in `lifecycle-ops.md`: abort FIRST, then re-wake. A single snapshot is
|
||||
never an abort basis ([org-internal #3215]).
|
||||
never an abort basis ([TT-3215]).
|
||||
|
||||
**Signal 3 — provider-level confirmation ([org-internal #2911] quota markers).** `GET
|
||||
**Signal 3 — provider-level confirmation ([TT-2911] quota markers).** `GET
|
||||
/provider` overlays active usage-limit cooldowns, so the dead provider is
|
||||
visible without reading logs:
|
||||
|
||||
@@ -86,7 +86,7 @@ date -d @$(($(curl -s "$BASE/provider?directory=$DIR" | jq '[.all[].quota.resetA
|
||||
```
|
||||
|
||||
**Log grep (fallback; the dev log is restart-truncated).** Patterns actually
|
||||
seen in the wild — [org-internal #3627] produced the first:
|
||||
seen in the wild — [TT-3627] produced the first:
|
||||
|
||||
```sh
|
||||
grep -E "usage limit reached|Go limit reached|Free limit reached|Account-level usage limit|GoUsageLimitError|FreeUsageLimitError|rate limited \(HTTP 429\)|insufficient_quota" \
|
||||
@@ -96,7 +96,7 @@ grep -E "usage limit reached|Go limit reached|Free limit reached|Account-level u
|
||||
```
|
||||
|
||||
The wall is only terminal after failover has exhausted the same-name pools
|
||||
([org-internal #2911] failover); the `retrying … on …` WARNs above tell you the pool was
|
||||
([TT-2911] failover); the `retrying … on …` WARNs above tell you the pool was
|
||||
already draining before it died.
|
||||
|
||||
## Recovery — abort (only if needed), re-wake on a known-good provider, inject facts
|
||||
@@ -130,7 +130,7 @@ curl -s "$BASE/provider?directory=$DIR" | jq -r \
|
||||
# own current model — it is generating by definition).
|
||||
```
|
||||
|
||||
([org-internal #3627]: opencode-go dead → re-woken on zhipuai-coding-plan/glm-5.3, since
|
||||
([TT-3627]: opencode-go dead → re-woken on zhipuai-coding-plan/glm-5.3, since
|
||||
renamed `zai-coding-plan`. Do NOT "wait for reset" as the default — weekly
|
||||
windows mean days.)
|
||||
|
||||
@@ -159,9 +159,9 @@ curl -s "$BASE/provider?directory=$DIR" | jq -r \
|
||||
**Step 3 — re-wake with a fact-baseline prompt.** Build the payload from a file
|
||||
(`jq --rawfile`, SKILL.md pitfall #7), same wake shape as
|
||||
`lifecycle-ops.md` but with the quota facts. The template also restates the
|
||||
completion-report protocol ([org-internal #2374]) so the recovery is self-contained: it
|
||||
completion-report protocol ([TT-2374]) so the recovery is self-contained: it
|
||||
assumes the original seed still contains the protocol block — if you are
|
||||
unsure it does (e.g. the worker was dispatched before [org-internal #3669] added the quota
|
||||
unsure it does (e.g. the worker was dispatched before [TT-3669] added the quota
|
||||
clause), the template's own block below carries it; fill
|
||||
`<BASE>`/`<LAUNCHER_SID>`/`<DIR>` with the orchestrator session's values:
|
||||
|
||||
@@ -176,7 +176,7 @@ cat > wake.txt <<'EOF'
|
||||
3. 从哪继续:<一件具体的下一步任务>。
|
||||
4. 证据规则:逐条到引用来源(issue 评论 / PR / 工件)核实后再行动,
|
||||
勿仅凭本基线行动。
|
||||
## 完成回报协议(重申 [org-internal #2374]/[org-internal #3669];不确定原始 seed 是否含协议块时以本节为准)
|
||||
## 完成回报协议(重申 [TT-2374]/[TT-3669];不确定原始 seed 是否含协议块时以本节为准)
|
||||
完成、阻塞或移交时,必须回报编排会话(你的唤醒者):
|
||||
POST <BASE>/session/<LAUNCHER_SID>/prompt_async?directory=<DIR>
|
||||
body: {"agent":"builder","model":{...},"parts":[{"type":"text","text":"<report>"}]}
|
||||
@@ -195,7 +195,7 @@ jq -n --rawfile p wake.txt '{agent:"builder",
|
||||
Then poll the tail (`limit=1`) until an assistant message appears, and keep
|
||||
expecting the completion-report per protocol — the re-woken worker owes you
|
||||
`status=done|blocked` like any other (the restated block in the template
|
||||
makes this hold even when the original seed predates [org-internal #3669]).
|
||||
makes this hold even when the original seed predates [TT-3669]).
|
||||
|
||||
## Prevention — before dispatch, and in the seed
|
||||
|
||||
@@ -213,7 +213,7 @@ If the intended provider is already quota-marked, dispatch on a different one
|
||||
|
||||
**Quota self-report clause (turns a silent death into a harvestable
|
||||
blocked).** The canonical clause text lives in `completion-report.md`
|
||||
§"Orchestrator side" (配额自报, [org-internal #3669]) — append it VERBATIM to the seed
|
||||
§"Orchestrator side" (配额自报, [TT-3669]) — append it VERBATIM to the seed
|
||||
prompt's completion-report block. Single source of truth: do not fork or
|
||||
restate the clause here; its blocked payload already follows the one-line
|
||||
key=value spec (`status=blocked reason=quota-exhausted summary=<provider +
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
> Extracted from headless-session-ops/SKILL.md (Launch a session for a specific ticket (#N)) — moved verbatim 2026-08-26, ticket [org-internal #3480].
|
||||
> Extracted from headless-session-ops/SKILL.md (Launch a session for a specific ticket (#N)) — moved verbatim 2026-08-26, ticket [TT-3480].
|
||||
|
||||
## Launch a session for a specific ticket (#N)
|
||||
|
||||
@@ -7,13 +7,13 @@ work a tracked issue. Compose the seed prompt **from the issue itself** so the
|
||||
new session starts with real context, and launch it on **the current session's
|
||||
model**.
|
||||
|
||||
0. **Owner check (MANDATORY pre-step, [org-internal #1803]).** Before creating anything,
|
||||
0. **Owner check (MANDATORY pre-step, [TT-1803]).** Before creating anything,
|
||||
verify no other live session already owns this ticket or code area —
|
||||
duplicate ownership is how [org-internal #1744]/[org-internal #1753] collided. The check spans four
|
||||
duplicate ownership is how [TT-1744]/[TT-1753] collided. The check spans four
|
||||
data sources; any live claim → **ABORT the launch and report the
|
||||
conflict**.
|
||||
|
||||
**Mechanized ([org-internal #3667])**: `bash script/session-conflicts.sh <N>` runs the
|
||||
**Mechanized ([TT-3667])**: `bash script/session-conflicts.sh <N>` runs the
|
||||
session-title scan (a), the branch scan (d), and the open-PR check (c)
|
||||
in one read-only pass (exit 4 = conflict, `--json` for a machine
|
||||
summary); the assignee/claim check (b) is `claim.sh`'s compare-and-swap
|
||||
@@ -23,7 +23,7 @@ model**.
|
||||
**a. Session-title scan (live session check).** The listing endpoint
|
||||
returns at most `limit` (default 100) sessions — on busy repos (300+ live
|
||||
sessions in one directory) that silently truncates and the scan misses
|
||||
owners ([org-internal #3190]). Non-range listing responses carry `X-Total-Count` (full
|
||||
owners ([TT-3190]). Non-range listing responses carry `X-Total-Count` (full
|
||||
filter population, untruncated) and `X-Has-More: true` (only when the
|
||||
page is truncated). Scan procedure: fetch page 1, and when
|
||||
`X-Has-More: true` is present re-fetch once with `limit=$TOTAL` — treat
|
||||
@@ -57,7 +57,7 @@ model**.
|
||||
the launch and report the conflict** (issue comment naming the owning
|
||||
session id). Do not launch a second session for the same ticket.
|
||||
|
||||
**b. Assignee / claim check ([org-internal #2297]).** Read the issue via
|
||||
**b. Assignee / claim check ([TT-2297]).** Read the issue via
|
||||
`工单 API(见 TERMINOLOGY)get(owner, repo, index: N)` (or `GET /api/v1/repos/$OWNER/$REPO/issues/$N`):
|
||||
- If `assignee` is set and is **not** the launching agent → **ABORT** and
|
||||
report (the ticket is already claimed).
|
||||
@@ -65,10 +65,10 @@ model**.
|
||||
and coordinate on the issue before proceeding.
|
||||
|
||||
**c. Open-PR check.** List open PRs referencing `#N` —
|
||||
`工单 API(见 TERMINOLOGY)search(q: "#N", type: "pulls", state: "open")` (API source)
|
||||
or `gitea_pull__list` — and **ABORT** if an open PR already covers the ticket.
|
||||
`GET <gitea-base-url>/api/v1/repos/issues/search?q="#N"&type=pulls&state=open`
|
||||
(API source) — and **ABORT** if an open PR already covers the ticket.
|
||||
|
||||
**d. Remote branch check ([org-internal #2297]).** A local branch is invisible to other
|
||||
**d. Remote branch check ([TT-2297]).** A local branch is invisible to other
|
||||
sessions — check the remote too:
|
||||
`git ls-remote origin 'workflow/*'` and scan for a branch tail covering `#N`.
|
||||
Also check the repo side locally: `git worktree list` +
|
||||
@@ -76,7 +76,7 @@ model**.
|
||||
|
||||
- A stale hit (session idle for hours / clearly abandoned) → do NOT
|
||||
hand-post a takeover comment (retired admin workaround — unauditable);
|
||||
dead-claim takeover is mechanized ([org-internal #3668]): `bash script/claim.sh
|
||||
dead-claim takeover is mechanized ([TT-3668]): `bash script/claim.sh
|
||||
takeover <ticket> <branch> --session-id <id>`. It enforces the
|
||||
evidence gate (branch ABSENT on origin AND (session 404 OR comment at
|
||||
least CLAIM_TAKEOVER_STALE_DAYS old)) and exits 10 when the evidence
|
||||
@@ -87,13 +87,13 @@ model**.
|
||||
§"Dead-claim takeover" (claim.sh header is normative).
|
||||
The runtime counterpart of this check is `core/rules/session-scope-guard.md`
|
||||
("One task, one owner"), injected into every session's prompt.
|
||||
- **Backend hard guard ([org-internal #1989]):** `POST /session` hard-rejects duplicate-ticket
|
||||
session creation with HTTP 400. The backend guard is **on by default ([org-internal #2350])**;
|
||||
- **Backend hard guard ([TT-1989]):** `POST /session` hard-rejects duplicate-ticket
|
||||
session creation with HTTP 400. The backend guard is **on by default ([TT-2350])**;
|
||||
set `enabled: false` in config to opt out. It fails open ONLY on defect
|
||||
paths (DB / config errors), never as a configured disable. The front-end
|
||||
soft check above is now backed by this backend hard check for defense in
|
||||
depth.
|
||||
- **Claim-first ([org-internal #2297]).** Claiming a ticket is one atomic 3-step action:
|
||||
- **Claim-first ([TT-2297]).** Claiming a ticket is one atomic 3-step action:
|
||||
(1) set the issue assignee to the working account, (2) post a claim comment
|
||||
naming the workflow branch and session id, (3) push the workflow branch to
|
||||
remote (`git push -u origin workflow/...`). The claim is valid ONLY when all
|
||||
@@ -101,7 +101,7 @@ model**.
|
||||
session until all three steps are done (see
|
||||
`core/rules/session-scope-guard.md` §"Claim-first"). If a collision HAS
|
||||
already happened, follow `rules/ownership-collision-runbook` (wiki, L2 on-demand).
|
||||
- **Provisioning after claim ([org-internal #3642]) is ONE command** — claim + worktree +
|
||||
- **Provisioning after claim ([TT-3642]) is ONE command** — claim + worktree +
|
||||
Tier-1 runs scaffold:
|
||||
`bash script/claim-provision.sh <N> workflow/<branch>` (runs claim.sh with
|
||||
exit codes passed through, attaches the session worktree to the claimed
|
||||
@@ -123,7 +123,7 @@ model**.
|
||||
- restate the **goal** in one sentence;
|
||||
- list the **constraints** and **acceptance criteria**;
|
||||
- cite every **wiki artifact path** / related issue referenced in the body
|
||||
(e.g. `{epic-slug}/dag`, `{epic-slug}/dag-nodes/{node-id}`, `[org-internal #1691]`);
|
||||
(e.g. `{epic-slug}/dag`, `{epic-slug}/dag-nodes/{node-id}`, `[TT-1691]`);
|
||||
- tell the new agent to follow the right pipeline skill for the work type
|
||||
(implement / bugfix / design / …).
|
||||
Write it to a file (handles newlines):
|
||||
@@ -141,16 +141,16 @@ your change — classify (pre-existing/flaky), file a BF/FT issue per
|
||||
core/rules/session-scope-guard.md, and continue this task. Do NOT fix
|
||||
unrelated failing tests in place.
|
||||
|
||||
## 完成回报协议 (mandatory, [org-internal #2374])
|
||||
## 完成回报协议 (mandatory, [TT-2374])
|
||||
|
||||
完成、阻塞、或移交时,向编排会话回报:
|
||||
POST <BASE>/session/<LAUNCHER_SID>/prompt_async?directory=<DIR>
|
||||
(编排目录未知时可用全局路由 POST <BASE>/prompt_async,body 携 sessionID,[org-internal #4307])
|
||||
(编排目录未知时可用全局路由 POST <BASE>/prompt_async,body 携 sessionID,[TT-4307])
|
||||
body: {"agent":"builder","model":{...},"parts":[{"type":"text","text":"<report>"}]}
|
||||
<report>: [#N] [<node-or-slug>] status=done|blocked|handoff branch=<ref> [pr=#<PR>] verify=<changed+typecheck> risk=<high|low> summary=<one line>
|
||||
约束:worker 只推分支不开 PR(PR 由编排串行开);交付推送前 test:changed+typecheck 须绿。若再遇配额/用量上限错误,立即回报 status=blocked reason=quota-exhausted summary=<provider 与重置提示>(branch=<ref> 必带)后停止,勿自行换模型重试。
|
||||
回报失败(非 2xx / 连接拒绝)→ 在本 issue(或父 Epic)发同内容评论兜底。
|
||||
决策边界([org-internal #2378]):遇方向性决策点 → status=blocked 回报,勿调 question。
|
||||
决策边界([TT-2378]):遇方向性决策点 → status=blocked 回报,勿调 question。
|
||||
EOF
|
||||
```
|
||||
|
||||
@@ -179,4 +179,4 @@ EOF
|
||||
|
||||
6. **Add the completion-report block to the seed prompt** (see next section) so
|
||||
the worker reports back when it finishes or blocks — without it, this
|
||||
orchestrator has no push channel and must poll forever ([org-internal #2374]).
|
||||
orchestrator has no push channel and must poll forever ([TT-2374]).
|
||||
|
||||
@@ -3,7 +3,7 @@ name: image-interpret
|
||||
description: >
|
||||
Use ONLY when the agent needs to read or analyze an image (screenshot,
|
||||
design mockup, UI capture, .png/.jpg/.webp file) but the active model lacks
|
||||
vision capability. Delegates to the Image Interpreter role (vision-capable
|
||||
vision capability. Delegates to the Tool role (image interpretation) (vision-capable
|
||||
model) which returns a structured text spec — layout regions, colors (hex),
|
||||
spacing (px), typography, component hierarchy, and responsive breakpoints.
|
||||
Do not use for non-image tasks or when the active model already supports
|
||||
@@ -31,7 +31,7 @@ role: Tool
|
||||
|
||||
You (the calling agent) cannot read images — your model has no vision. Any
|
||||
task that requires *seeing* a visual artifact must be delegated to the
|
||||
**Image Interpreter** role, which runs on a vision-capable model and returns a
|
||||
**Tool** role (image interpretation), which runs on a vision-capable model and returns a
|
||||
structured text description you can act on.
|
||||
|
||||
Trigger situations:
|
||||
@@ -64,7 +64,7 @@ Trigger situations:
|
||||
)
|
||||
```
|
||||
|
||||
4. **Consume the returned text spec.** The Image Interpreter returns a
|
||||
4. **Consume the returned text spec.** The Tool sub-agent (image interpretation) returns a
|
||||
structured description only — it cannot write code or artifacts. Use the
|
||||
returned spec to drive your own work (code generation, design review,
|
||||
planning).
|
||||
@@ -74,7 +74,7 @@ Trigger situations:
|
||||
|
||||
## Notes
|
||||
|
||||
- The Image Interpreter is **read-only** — it describes images, it does not edit
|
||||
- The Tool sub-agent (image interpretation) is **read-only** — it describes images, it does not edit
|
||||
files or write code.
|
||||
- One delegation per distinct visual question. Batch multiple images into a
|
||||
single delegation only when they must be compared.
|
||||
|
||||
@@ -8,7 +8,7 @@ description: >
|
||||
self-checks against the relevant checklist before handing off to code
|
||||
review.
|
||||
# `stage` is intentionally omitted: `implement` is a production-phase name the
|
||||
# stage registry rules invalid post-[org-internal #3072] phase 3 (see
|
||||
# stage registry rules invalid post-[TT-3072] phase 3 (see
|
||||
# core/schemas/workflow-routing.schema.json stage enum — production-phase
|
||||
# names are "no longer valid anywhere"). The implement skill has no registry
|
||||
# gate id; the gates it feeds into are `review-code` and `verify`.
|
||||
@@ -77,7 +77,7 @@ In **pipeline mode** (work item from iteration plan), follow the standard precon
|
||||
|
||||
**On-demand references**: each mode's phase-by-phase detail (templates, prompts, orchestration flows, historical notes) lives in `reference/{mode}-mode.md`, NOT injected — read it at mode entry. Full read-timing table: References section.
|
||||
|
||||
> **Progressive disclosure ([org-internal #3734])**: when dispatching a Developer scoped to
|
||||
> **Progressive disclosure ([TT-3734])**: when dispatching a Developer scoped to
|
||||
> one mode, pass `skills: ["implement:mode-bugfix"]` (preamble + that
|
||||
> mode's workflow only) instead of the full body; pipeline-mode dispatches
|
||||
> should also carry `pipeline-detection`
|
||||
@@ -97,12 +97,12 @@ The Developer is responsible for:
|
||||
- Writing code that faithfully implements the design.
|
||||
- Running typecheck, lint, and tests to self-verify.
|
||||
- Self-checking against the relevant checklist before handoff.
|
||||
- Persisting the final report to disk before returning — worker-report persistence ([org-internal #2847], see `../_shared/worker-report-persistence.md`).
|
||||
- Persisting the final report to disk before returning — worker-report persistence ([TT-2847], see `../_shared/worker-report-persistence.md`).
|
||||
- Writing no more and no less than the work item scope — no opportunistic refactoring of unrelated code.
|
||||
|
||||
The Builder's role is to validate the implementation output and pass it to code review. The Builder MUST NOT write or revise implementation code.
|
||||
|
||||
### Pre-flight checklist injection ([org-internal #2599])
|
||||
### Pre-flight checklist injection ([TT-2599])
|
||||
|
||||
Before dispatching ANY Developer (or Tester) sub-agent — in every mode (implement / bugfix / refactor / port; pipeline or standalone) — the orchestrator resolves the ticket's route (the Process Assessment Gate Step 0 already resolves the Kind/* route) and reads `<instance-root>/workflow-routing.yaml` `routes.{Kind}.preflight`. When the list is non-empty, prepend it to the sub-agent's task prompt as:
|
||||
|
||||
@@ -162,7 +162,7 @@ Standard workflow for work items from an approved iteration plan. Full phase det
|
||||
>
|
||||
> At Phase 6 handoff, pass `mode: "dag-task"` to review-code (its DAG Task Mode keys off the same frozen-DAG-copy detection).
|
||||
|
||||
> **Legacy pipeline preconditions retired ([org-internal #3072] phase 3, 2026-08-21)**: tiered artifact-existence and review-convergence checks belonged to the archived legacy pipeline. Live input modes: DAG task mode (above) and standalone modes (the request itself is the spec). Historical tiered publish targets: `reference/implement-mode.md` § Legacy notes.
|
||||
> **Legacy pipeline preconditions retired ([TT-3072] phase 3, 2026-08-21)**: tiered artifact-existence and review-convergence checks belonged to the archived legacy pipeline. Live input modes: DAG task mode (above) and standalone modes (the request itself is the spec). Historical tiered publish targets: `reference/implement-mode.md` § Legacy notes.
|
||||
|
||||
Before starting implementation, confirm:
|
||||
|
||||
@@ -186,13 +186,13 @@ Every gate below is hard — agents rationalize skipping exactly these. Full det
|
||||
4. **Phase 4 — Self-Check** (all mandatory):
|
||||
1. `bun typecheck` (or project-equivalent) — zero errors.
|
||||
2. `bun oxlint --deny-warnings` (repo root — the review-code mechanical gate's canonical lint invocation; `bun lint` is the package-script alias) — zero errors.
|
||||
3. `bun run test:changed` (or project-equivalent; full suite `bun run test:parallel` is verify's job, not a per-revision gate, [org-internal #2598]) — all tests pass.
|
||||
3. `bun run test:changed` (or project-equivalent; full suite `bun run test:parallel` is verify's job, not a per-revision gate, [TT-2598]) — all tests pass.
|
||||
4. Post-deletion cleanup (when any code was removed): re-run lint + typecheck to catch orphaned imports/variables/type references.
|
||||
Then self-check `core/checklists/implementation.md`; every new function/method/exported API has ≥ 1 test; interface promises cross-checked against the node's edge contracts. **Review-readiness GATE**: self-attest `core/checklists/code-review.md` (COR, DGN, SEC, PERF, TST, STY, DBT, A11Y, DOC, TRC), record pass/fail per dimension in the Phase 5 report; handoff requires **0 BLOCKERs and 0 MAJORs** — if you can find a MAJOR, the formal review will too; fix it now.
|
||||
5. **Phase 4.5 — Iteration Completion Commit**: after ALL work items in the iteration pass Phase 4, commit with format `[{chunk-id}][{iteration}] {summary}`; commit body REQUIRED for non-trivial commits (> 1 file or > 20 LOC): What (files + purpose + the `WI-{NNN}` ID — code-review TRC 10.1), Why (design/REQ motivation), Evidence (test names / verification commands). Full rules: `reference/implement-mode.md` § Phase 4.5.
|
||||
6. **Phase 4.6 — Issue Checklist Sync (progressive)**: after committing, mark items this iteration delivered `- [x]` + `_(commit {sha}: file/component)_` per the `issue-checklist-sync` L1 rule; do NOT touch items outside this iteration's scope.
|
||||
7. **Phase 4.7 — PR-Creation Sync**: the session pushes its branch and reports `status=done branch=<ref> verify=… risk=…` — the orchestrator opens the PR (serially per TD-678/[org-internal #4425]) and applies the `Risk/*` label from the report's `risk=` hint, computed per the risk-classifier frozen table (`HIGH_RISK_GLOBS` in `.gitea/scripts/risk-classifier.ts`: core/migrations/deploy/`core/rules/**`/`.gitea/workflows/**` → `Risk/High`, else `Risk/Low`); `Risk/High` PRs merge manually by design. Once the PR exists, ensure `## 当前状态` exists (PR / 代码评审 / CI rows are written by the `status-sync` poller, NOT by hand); append the PR reference to the matching Epic task-list row. **Never hand-sync main into the PR branch** — that is the keep-mergeable workflow's job. Detail: `reference/implement-mode.md` § Phase 4.6 / § Phase 4.7.
|
||||
8. **Phase 5 — Report**: implementation report with AC → test traceability (template: `reference/implement-mode.md` § Phase 5). **Persist before returning ([org-internal #2847])** — the Developer's LAST action before returning the report: write it to `<runs-root>/{slug}/workers/{chunk-id}-worker-{seq}.md` (Tier 1 run workspace) else `/tmp/octopus/{chunk-id}-worker-{seq}.md` (`../_shared/worker-report-persistence.md`). The persisted copy is the report of record — applies to EVERY mode's report phase.
|
||||
7. **Phase 4.7 — PR-Creation Sync**: the session pushes its branch and reports `status=done branch=<ref> verify=… risk=…` — the orchestrator opens the PR (serially per TD-678/[TT-4425]) and applies the `Risk/*` label from the report's `risk=` hint, computed per the risk-classifier frozen table (`HIGH_RISK_GLOBS` in `.gitea/scripts/risk-classifier.ts`: core/migrations/deploy/`core/rules/**`/`.gitea/workflows/**` → `Risk/High`, else `Risk/Low`); `Risk/High` PRs merge manually by design. Once the PR exists, ensure `## 当前状态` exists (PR / 代码评审 / CI rows are written by the `status-sync` poller, NOT by hand); append the PR reference to the matching Epic task-list row. **Never hand-sync main into the PR branch** — that is the keep-mergeable workflow's job. Detail: `reference/implement-mode.md` § Phase 4.6 / § Phase 4.7.
|
||||
8. **Phase 5 — Report**: implementation report with AC → test traceability (template: `reference/implement-mode.md` § Phase 5). **Persist before returning ([TT-2847])** — the Developer's LAST action before returning the report: write it to `<runs-root>/{slug}/workers/{chunk-id}-worker-{seq}.md` (Tier 1 run workspace) else `/tmp/octopus/{chunk-id}-worker-{seq}.md` (`../_shared/worker-report-persistence.md`). The persisted copy is the report of record — applies to EVERY mode's report phase.
|
||||
9. **Phase 6 — Handoff to Code Review**: present the report; signal readiness via `signal_stage_done`. Do NOT mark the work item complete until code review passes.
|
||||
|
||||
#### Tester focus & Common Rationalizations
|
||||
@@ -216,7 +216,7 @@ The regression test MUST fail before the fix — the Tester dispatches between P
|
||||
2. **Phase 2 — Isolate Root Cause**: trace symptom → proximate cause → root cause (RCA template: `reference/bugfix-mode.md` § Phase 2); fixing a symptom → stop, go deeper; not found after 3 levels of indirection → pause and report, no surface-level patch. Then evaluate routing (below).
|
||||
3. **Phase 3 — Write a Regression Test**: exercise the exact bug path with the failing inputs; it MUST fail with the bug's symptom NOW, before the fix (already passing → the test does not cover the bug, rewrite it; no failing test possible → most targeted test, marked `[flaky]`).
|
||||
4. **Phase 4 — Fix**: minimum change resolving the root cause; one conceptual change per fix — no bundled refactoring, style changes, or "while I'm here" improvements (root cause in a different file → fix it there). Run the regression test (MUST pass) + relevant unit tests.
|
||||
5. **Phase 5 — Self-Check & Report**: `bun typecheck`; `bun oxlint --deny-warnings`; `bun run test:changed` (all pass; full suite belongs to verify); verify `core/checklists/bugfix.md`; publish the bugfix report as wiki page `{slug}/bugfix-report` (template: `reference/bugfix-mode.md` § Bugfix Report); persist per the Phase 5 persistence rule (Mode: implement, [org-internal #2847]).
|
||||
5. **Phase 5 — Self-Check & Report**: `bun typecheck`; `bun oxlint --deny-warnings`; `bun run test:changed` (all pass; full suite belongs to verify); verify `core/checklists/bugfix.md`; publish the bugfix report as wiki page `{slug}/bugfix-report` (template: `reference/bugfix-mode.md` § Bugfix Report); persist per the Phase 5 persistence rule (Mode: implement, [TT-2847]).
|
||||
6. **Phase 5.5 — Issue Checklist Sync (standalone bugfix)**: sync the source issue at each transition (commit / PR / review / CI / close) per the `issue-checklist-sync` L1 rule and its standalone-flow table.
|
||||
7. **Phase 6 — Approval**: present the report (prompt: `reference/bugfix-mode.md` § Phase 6 — Approval).
|
||||
|
||||
@@ -224,14 +224,14 @@ The regression test MUST fail before the fix — the Tester dispatches between P
|
||||
|
||||
Full escalate/stay criteria: `reference/bugfix-mode.md` § Routing Decision. In short — **escalate to pipeline** on ANY of: ≥ 5 files · ≥ 2 modules/components · design-level root cause · data migration / schema change · public-API / contract change · dependency change · > 50 lines · user requests full-process; **stay standalone** only when ALL the opposites hold. If uncertain, escalate — a false escalation costs review rounds; a false standalone decision skips quality gates.
|
||||
|
||||
**Big-bug relabel rule ([org-internal #3061])** — before the generic escalation above, split the triggers by kind:
|
||||
**Big-bug relabel rule ([TT-3061])** — before the generic escalation above, split the triggers by kind:
|
||||
|
||||
- **Design-level triggers** (root cause is a design decision — protocol / schema / architecture; shared-contract or public-API change; data migration): do NOT push through bugfix — **relabel the ticket `Kind/Feature`** and reroute via Step 0 (DAG route; 1–3 node small DAG expected); repro + root-cause notes become node input.
|
||||
- **Mechanical size triggers only** (many files / lines, same design): stay in bugfix — batch into iterations, keep review-code + verify. Scale alone never justifies a relabel.
|
||||
|
||||
#### Pipeline Mode (bugfix)
|
||||
|
||||
> **Legacy path retired ([org-internal #3072] phase 3)**: the requirements → design → review → plan front-end was archived; a big bug needing a design-level decision relabels `Kind/Feature` into the DAG route (big-bug relabel rule above).
|
||||
> **Legacy path retired ([TT-3072] phase 3)**: the requirements → design → review → plan front-end was archived; a big bug needing a design-level decision relabels `Kind/Feature` into the DAG route (big-bug relabel rule above).
|
||||
|
||||
When a bugfix escalates beyond standalone scope, the bug report becomes a pipeline input; the bugfix phases (reproduce, root cause, regression test, fix) are embedded within the implement stage, and review-code + verify remain mandatory. On the DAG route the node spec lives in `{epic-slug}/dag`; the Developer follows bugfix Phases 1–6 as the implementation method, then produces the standard implementation report (Mode: implement, Phase 5).
|
||||
|
||||
@@ -259,7 +259,7 @@ Restructure existing code without changing observable behavior — the existing
|
||||
1. **Phase 1 — Scope & Baseline**: map exact files + dependents; run `bun run test:parallel` (the refactor baseline legitimately needs the full suite) — ANY pre-existing failure → stop ("Cannot begin refactoring with failing tests. Fix them first."). Capture baseline: test count, coverage, optional complexity (template: `reference/refactor-mode.md` § Baseline).
|
||||
2. **Phase 2 — Define Target Pattern**: Extract / Inline / Rename / Move / Replace / Simplify / Upgrade, with one-sentence goal + success criteria (all tests pass unchanged; structural goal met; coverage does not decrease). Pipeline mode: align with the node spec + contracts, or justify in the report.
|
||||
3. **Phase 3 — Decompose into Steps**: smallest individually-verifiable steps (each reversible, suite-passing, ONE conceptual transformation); present the plan before executing (user may approve / reorder / reject). **If > 10 steps, the scope is too large — split into multiple sessions.**
|
||||
4. **Phase 4 — Incremental Execution**: per step — transform, run `bun run test:changed` (ALL pass; per-step scoped reruns — full suite is verify's job, [org-internal #2598]), commit `refactor: {what} from {where}`. **If FAIL: revert immediately** — do NOT fix the test or code within the same step; find a smaller decomposition (exception: fix a flaky test first as a prerequisite step, then retry).
|
||||
4. **Phase 4 — Incremental Execution**: per step — transform, run `bun run test:changed` (ALL pass; per-step scoped reruns — full suite is verify's job, [TT-2598]), commit `refactor: {what} from {where}`. **If FAIL: revert immediately** — do NOT fix the test or code within the same step; find a smaller decomposition (exception: fix a flaky test first as a prerequisite step, then retry).
|
||||
5. **Phase 5 — Final Validation**: `bun run test:parallel` all pass; `bun typecheck` zero errors; `bun oxlint --deny-warnings` zero errors; coverage MUST NOT decrease vs baseline (±1% noise).
|
||||
6. **Phase 6 — Report**: before/after metrics, steps executed, verification results, design deviations (template: `reference/refactor-mode.md` § Refactor Report).
|
||||
7. **Phase 7 — Approval**: present the report (prompt: `reference/refactor-mode.md` § Phase 7 — Approval). Route to code review if > 50 lines or ≥ 5 files.
|
||||
@@ -336,7 +336,7 @@ Not all work items involve writing new code — some are refactoring, bugfix, or
|
||||
- `core/skills/browser-debug/SKILL.md` — Interactive browser verification (for frontend work items) and UI bug reproduction (bugfix Phase 1)
|
||||
- `core/skills/review-code/SKILL.md` — Code review (next step after implementation)
|
||||
- `core/skills/verify/SKILL.md` — Integration + fidelity verification (pipeline-mode bugfix, large port)
|
||||
- `<instance-root>/archive/skills/` — Legacy requirements/design/plan/roadmap skills (archived [org-internal #3072] phase 3; their templates moved to `<instance-root>/archive/templates/`)
|
||||
- `<instance-root>/archive/skills/` — Legacy requirements/design/plan/roadmap skills (archived [TT-3072] phase 3; their templates moved to `<instance-root>/archive/templates/`)
|
||||
- `reference/source-analysis.md` — Port Phase A1, A1.5, A1.7, A1.8 detailed processes & templates
|
||||
- `reference/mapping-and-design.md` — Port Phase A2, A3, A4 detailed processes & templates
|
||||
- `reference/large-port-pipeline.md` — Port Phase B1–B4 detailed processes
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
> Extracted from implement/SKILL.md (Mode: bugfix) — moved verbatim 2026-08-25, ticket [org-internal #3381].
|
||||
> Extracted from implement/SKILL.md (Mode: bugfix) — moved verbatim 2026-08-25, ticket [TT-3381].
|
||||
|
||||
### Mode: bugfix
|
||||
|
||||
@@ -104,15 +104,15 @@ Phase 2 and Phase 4, not after the fix:
|
||||
[Worker: developer] Phase 1 reproduce + Phase 2 root cause
|
||||
→ write repro-notes (reproduction steps, root cause, bug path,
|
||||
expected behavior)
|
||||
↓ persist: wiki page `{slug}/repro-notes` (gitea_wiki__create_page)
|
||||
↓ persist: wiki page `{slug}/repro-notes` (`POST .../wiki/new`, body `content_base64`)
|
||||
[Worker: tester] read repro-notes → Phase 3 write failing regression test
|
||||
(confirms FAIL before fix)
|
||||
↓ persist: wiki page `{slug}/test-report` (gitea_wiki__create_page, failing test confirmed)
|
||||
↓ persist: wiki page `{slug}/test-report` (`POST .../wiki/new`, body `content_base64`, failing test confirmed)
|
||||
[Worker: developer] Phase 4 fix → run test:changed to green
|
||||
→ write impl-notes (post-fix behavior contract)
|
||||
↓ persist: wiki page `{slug}/impl-notes` (gitea_wiki__create_page, post-fix behavior contract)
|
||||
↓ persist: wiki page `{slug}/impl-notes` (`POST .../wiki/new`, body `content_base64`, post-fix behavior contract)
|
||||
[Worker: tester] supplement boundary regression tests → run test:changed
|
||||
↓ persist: update wiki page `{slug}/test-report` (gitea_wiki__update_page, final)
|
||||
↓ persist: update wiki page `{slug}/test-report` (`PATCH .../wiki/page/{mangled-name}`, omit `title`, body `content_base64` — final)
|
||||
— consumed by the human stakeholder / next iteration planning for DoD regression-test evidence
|
||||
```
|
||||
|
||||
@@ -182,7 +182,7 @@ If the Developer is uncertain, escalate. A false pipeline escalation costs a few
|
||||
extra review rounds. A false standalone decision risks missing a quality gate on
|
||||
a complex change.
|
||||
|
||||
**Big-bug relabel rule ([org-internal #3061])** — before the generic escalation below, split
|
||||
**Big-bug relabel rule ([TT-3061])** — before the generic escalation below, split
|
||||
the triggers by kind:
|
||||
|
||||
- **Design-level triggers** (root cause is a design decision — protocol /
|
||||
@@ -449,7 +449,7 @@ resolves it by permitting triage but forbidding deferral.
|
||||
|
||||
#### Pipeline Mode (bugfix)
|
||||
|
||||
> **Legacy path retired ([org-internal #3072] phase 3, 2026-08-21)**: the full
|
||||
> **Legacy path retired ([TT-3072] phase 3, 2026-08-21)**: the full
|
||||
> requirements-elicitation → design → review-artifact(design-space) →
|
||||
> plan-iterations → review-artifact(plan) front-end was archived
|
||||
> (`<instance-root>/archive/skills/`). A big bug that needs a design-level decision
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
> Extracted from implement/SKILL.md (Mode: implement) — moved verbatim 2026-08-25, ticket [org-internal #3381].
|
||||
> Extracted from implement/SKILL.md (Mode: implement) — moved verbatim 2026-08-25, ticket [TT-3381].
|
||||
|
||||
### Mode: implement (default)
|
||||
|
||||
@@ -8,7 +8,7 @@ and self-verify before passing to code review.
|
||||
|
||||
#### Pre-flight
|
||||
|
||||
The pre-flight self-check prompt format ([org-internal #2599]), prepended to the Developer
|
||||
The pre-flight self-check prompt format ([TT-2599]), prepended to the Developer
|
||||
sub-agent's task prompt when `routes.{Kind}.preflight` is non-empty:
|
||||
|
||||
```
|
||||
@@ -75,7 +75,7 @@ Developer is structurally biased to miss.
|
||||
|
||||
#### Preconditions
|
||||
|
||||
> **Publish target (tiered targeting retired, [org-internal #3072] phase 3)**: the
|
||||
> **Publish target (tiered targeting retired, [TT-3072] phase 3)**: the
|
||||
> `Size/*`-tiered publish rule (`rules/workflow-routing.md` §"Publish target
|
||||
> by Size/* tier — RETIRED") was retired with the legacy producer skills.
|
||||
> Artifacts publish where the live mode puts them: DAG task mode → node spec
|
||||
@@ -125,7 +125,7 @@ Developer is structurally biased to miss.
|
||||
|
||||
Before starting implementation, confirm:
|
||||
|
||||
> **Legacy pipeline preconditions retired ([org-internal #3072] phase 3, 2026-08-21)**: the
|
||||
> **Legacy pipeline preconditions retired ([TT-3072] phase 3, 2026-08-21)**: the
|
||||
> tier-dependent requirements/design/plan artifact-existence checks and the
|
||||
> design-space / iteration-plan review-convergence checks that used to head
|
||||
> this list belonged to the archived legacy pipeline (`<instance-root>/archive/`).
|
||||
@@ -162,7 +162,7 @@ the work-item list from the frozen DAG copy: the ready/pending task nodes in
|
||||
`{epic-slug}/dag` (via `wiki 读写 API(见 TERMINOLOGY)`), cross-checked against the
|
||||
node tickets on the Epic's `## DAG 状态` table. (Legacy tier-based resolution
|
||||
via `{slug}/04-plan-04-iteration-assignment` was archived 2026-08-21,
|
||||
[org-internal #3072] phase 3.) Present the current ready nodes for selection:
|
||||
[TT-3072] phase 3.) Present the current ready nodes for selection:
|
||||
|
||||
```
|
||||
Current iteration: Iteration {N}: {Goal}
|
||||
@@ -346,7 +346,7 @@ a one-pass implementation into a multi-round review.
|
||||
| "Design is ambiguous here, I'll pick the obvious option" | Inventing a design decision is a Phase 2 abort condition. Flag the gap; do not guess. |
|
||||
| "Already manually verified it works" | Manual ≠ systematic — no record, can't re-run, can't bisect. `bun run test:changed` is the evidence the report demands. |
|
||||
| "Report is busywork, the diff speaks for itself" | No report → review-code cannot trace AC→test. Phase 5 is the handoff contract; skip it and the review stalls. |
|
||||
| "X× improvement — assumed, no measurement" | Quick-measure before it becomes an AC. Unverified assumptions in ACs waste framing cost ([org-internal #1932]: YAML token density assumed 2-3×, measured 0.95 — hypothesis rejected by data). |
|
||||
| "X× improvement — assumed, no measurement" | Quick-measure before it becomes an AC. Unverified assumptions in ACs waste framing cost ([TT-1932]: YAML token density assumed 2-3×, measured 0.95 — hypothesis rejected by data). |
|
||||
|
||||
---
|
||||
|
||||
@@ -463,14 +463,14 @@ waiting for the final verify gate.
|
||||
|
||||
The session pushes its branch and reports `status=done branch=<ref> verify=…
|
||||
risk=…`; the orchestrator admits the PR (serially, one open at a time) —
|
||||
workers never open PRs (TD-678/[org-internal #4425]; `uncoordinated` self-open only when
|
||||
workers never open PRs (TD-678/[TT-4425]; `uncoordinated` self-open only when
|
||||
the orchestrator is unreachable). Once that PR exists, update the source
|
||||
issue so stakeholders see the mergeable state without waiting for code
|
||||
review. Mandated by the `issue-checklist-sync` L1 rule; skip if no source
|
||||
issue exists.
|
||||
|
||||
> PR shape per mode: default = one 1:1 PR per task (body carries the worker
|
||||
> report); batch-mode epics ([org-internal #3731], per-epic opt-in) = the orchestrator
|
||||
> report); batch-mode epics ([TT-3731], per-epic opt-in) = the orchestrator
|
||||
> composes ONE batch PR per iteration via the `land-batch` skill. This phase
|
||||
> then runs per member issue as usual (N times), each pointing at its PR
|
||||
> (batch: the single batch PR); the poller writes the PR/CI/review rows
|
||||
@@ -499,8 +499,8 @@ issue exists.
|
||||
retired — each one re-triggered the full CI surface for near-zero re-tested
|
||||
risk.
|
||||
|
||||
> **Kanban column lifecycle**: automated (`工单 API(见 TERMINOLOGY)create` → Backlog,
|
||||
> `gitea_pull__create` → Review; no manual moves). Single shared reference:
|
||||
> **Kanban column lifecycle**: automated (`POST <gitea-base-url>/api/v1/repos/{owner}/{repo}/issues` → Backlog,
|
||||
> `POST .../pulls` → Review; no manual moves). Single shared reference:
|
||||
> `_shared/gitea-write-patterns.md` Pattern 7.5; column semantics: wiki
|
||||
> `kanban-lifecycle`.
|
||||
|
||||
@@ -549,7 +549,7 @@ Produce an implementation report:
|
||||
**Handoff**: Ready for `core/skills/review-code/SKILL.md`
|
||||
```
|
||||
|
||||
**Persist before returning ([org-internal #2847])**: the Developer MUST write the final
|
||||
**Persist before returning ([TT-2847])**: the Developer MUST write the final
|
||||
report above to disk as its LAST action, BEFORE returning it —
|
||||
`<runs-root>/{slug}/workers/{chunk-id}-worker-{seq}.md` when the Tier 1
|
||||
run workspace exists, else `/tmp/octopus/{chunk-id}-worker-{seq}.md`
|
||||
@@ -582,7 +582,7 @@ To notify workflow completion, call the `signal_stage_done` tool.
|
||||
|
||||
#### Legacy notes
|
||||
|
||||
> **Publish target (tiered targeting retired, [org-internal #3072] phase 3)**: the
|
||||
> **Publish target (tiered targeting retired, [TT-3072] phase 3)**: the
|
||||
> `Size/*`-tiered publish rule (`rules/workflow-routing.md` §"Publish target
|
||||
> by Size/* tier — RETIRED") was retired with the legacy producer skills.
|
||||
> Artifacts publish where the live mode puts them: DAG task mode → node spec
|
||||
|
||||
@@ -155,7 +155,7 @@ analysis:
|
||||
|
||||
## Phase B3 — Handoff to DAG Decomposition
|
||||
|
||||
> Legacy note ([org-internal #3072] phase 3, 2026-08-21): this handoff used to target the
|
||||
> Legacy note ([TT-3072] phase 3, 2026-08-21): this handoff used to target the
|
||||
> archived `roadmap` skill; it now targets `analyze-dag`.
|
||||
|
||||
Present the source analysis and request task-DAG decomposition:
|
||||
@@ -194,7 +194,7 @@ core/skills/implement/SKILL.md
|
||||
|
||||
(The legacy per-chunk `requirements-elicitation` → `design` →
|
||||
`review-artifact(design-space)` → `plan-iterations` → `review-artifact(plan)`
|
||||
front-end was archived 2026-08-21, [org-internal #3072] phase 3 — `<instance-root>/archive/`.)
|
||||
front-end was archived 2026-08-21, [TT-3072] phase 3 — `<instance-root>/archive/`.)
|
||||
|
||||
### implement
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
> Extracted from implement/SKILL.md (Mode: port) — moved verbatim 2026-08-25, ticket [org-internal #3381].
|
||||
> Extracted from implement/SKILL.md (Mode: port) — moved verbatim 2026-08-25, ticket [TT-3381].
|
||||
|
||||
### Mode: port
|
||||
|
||||
@@ -274,7 +274,7 @@ port (source analysis)
|
||||
→ verify (integration + fidelity)
|
||||
```
|
||||
|
||||
> Legacy diagram (archived [org-internal #3072] phase 3): the former per-chunk pipeline ran
|
||||
> Legacy diagram (archived [TT-3072] phase 3): the former per-chunk pipeline ran
|
||||
> requirements-elicitation → design → review (target: design-space) →
|
||||
> plan-iterations → review (target: plan) → implement → review-code. Those
|
||||
> skills/targets are archived (`<instance-root>/archive/`); the live path is the
|
||||
@@ -286,7 +286,7 @@ port (source analysis)
|
||||
| B1.5 | **GATE** — 10-dimensional peer review of source analysis | `reference/large-port-pipeline.md` |
|
||||
| B1.7+B1.8 | Target surface & capability boundary as formal artifacts for peer review | `reference/large-port-pipeline.md` |
|
||||
| B2 | Self-check source analysis against port checklist | `reference/large-port-pipeline.md` |
|
||||
| B3 | Handoff to analyze-dag — decompose by source module into DAG nodes (legacy: roadmap skill, archived [org-internal #3072] phase 3) | `reference/large-port-pipeline.md` |
|
||||
| B3 | Handoff to analyze-dag — decompose by source module into DAG nodes (legacy: roadmap skill, archived [TT-3072] phase 3) | `reference/large-port-pipeline.md` |
|
||||
| B4 | Per-node DAG task route: implement → review-code (the review-dag single gate replaces the legacy design-space + plan reviews at the Epic level) | `reference/large-port-pipeline.md` |
|
||||
| B5 | Verify — integration + fidelity, every `FID-*` traced to a passing test | `reference/fidelity-verification.md` |
|
||||
| B6 | **Final Approval** — consolidated port report | *(inline below)* |
|
||||
@@ -324,7 +324,7 @@ Present source analysis summary and request task-DAG decomposition. The
|
||||
Builder routes to `core/skills/analyze-dag/SKILL.md` with slug
|
||||
`port-{name}` (nodes per source module; the source analysis supplies node
|
||||
ACs and edge contracts). (Legacy: this handed off to the archived `roadmap`
|
||||
skill — `<instance-root>/archive/skills/roadmap/`, [org-internal #3072] phase 3.) See
|
||||
skill — `<instance-root>/archive/skills/roadmap/`, [TT-3072] phase 3.) See
|
||||
`reference/large-port-pipeline.md` for the handoff format.
|
||||
|
||||
##### Phase B4 — Per-Node Pipeline
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
> Extracted from implement/SKILL.md (Mode: refactor) — moved verbatim 2026-08-25, ticket [org-internal #3381].
|
||||
> Extracted from implement/SKILL.md (Mode: refactor) — moved verbatim 2026-08-25, ticket [TT-3381].
|
||||
|
||||
### Mode: refactor
|
||||
|
||||
@@ -234,7 +234,7 @@ After all steps are complete:
|
||||
{If the refactoring changes the internal architecture in a way that merits an
|
||||
ADR, reference the ADR. **Deprecated:** `.artifacts/{slug}/design/adr/{NNNN}-*.md`
|
||||
→ ADRs now live on the Gitea wiki at page `{slug}/03-adr-{NNNN}-{title}`,
|
||||
readable via `gitea_wiki__get_page`. Or "None".}
|
||||
readable via `GET <gitea-base-url>/api/v1/repos/{owner}/{repo}/wiki/page/{mangled-name}`. Or "None".}
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
> Extracted from implement/SKILL.md (Pipeline Work Item Detection) — moved verbatim 2026-08-25, ticket [org-internal #3381].
|
||||
> Extracted from implement/SKILL.md (Pipeline Work Item Detection) — moved verbatim 2026-08-25, ticket [TT-3381].
|
||||
|
||||
## Pipeline Work Item Detection
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: land-batch
|
||||
description: >
|
||||
Use ONLY when the orchestrator lands the finished task branches of one DAG
|
||||
iteration as a single batch PR ([org-internal #3731] batch-landing pilot). Composes
|
||||
iteration as a single batch PR ([TT-3731] batch-landing pilot). Composes
|
||||
path-disjoint member branches via the deterministic batch-compose script,
|
||||
pre-validates locally, opens ONE PR for N tasks (one CI fan-out instead of
|
||||
N on the single-runner pool), pastes each member's review synthesis into
|
||||
@@ -27,18 +27,18 @@ role: Producer
|
||||
(single writer at iteration close — the same role that already owns uniform
|
||||
merge/close). `workflow/batch/*` branches are NOT claim branches: no
|
||||
`claim.sh` interaction, no assignee; the orchestrator is the only composer.
|
||||
Pilot charter: the decision comment on [org-internal #3731] (scope, opt-in protocol, cap,
|
||||
Pilot charter: the decision comment on [TT-3731] (scope, opt-in protocol, cap,
|
||||
success criteria) — this skill implements that charter, not the epic's
|
||||
frozen DAG v1 (which covers only the merge-coordinator nodes N-01..04).
|
||||
|
||||
## Applicability: post-hoc composition only (topology B)
|
||||
|
||||
Two batch shapes exist ([org-internal #3731] charter addendum, comment 39347):
|
||||
Two batch shapes exist ([TT-3731] charter addendum, comment 39347):
|
||||
|
||||
- **Topology A — single-session mono-branch batch**: one session owns every
|
||||
ticket from inception and writes them on ONE branch (instance: PR [org-internal #3861],
|
||||
ticket from inception and writes them on ONE branch (instance: PR [TT-3861],
|
||||
audit-h1). Hand composition is natural there — do NOT force this skill on
|
||||
it; record the outcome on [org-internal #3731] as a manual-batch datum instead.
|
||||
it; record the outcome on [TT-3731] as a manual-batch datum instead.
|
||||
- **Topology B — parallel workers, post-hoc composition**: workers finish on
|
||||
SEPARATE branches at different times; the orchestrator composes at
|
||||
iteration close. This is the skill's ONLY applicability — cross-branch
|
||||
@@ -173,7 +173,7 @@ Do NOT hand-merge, do NOT hand-sync main into the batch branch.
|
||||
|
||||
Member issues auto-close via the English keywords; their `## 当前状态`
|
||||
PR/代码评审/CI rows fan out to EVERY close ref (status-sync poller Wide
|
||||
behavior — requires [org-internal #3867], merged 2026-08-31). `task done ≡ PR merged`
|
||||
behavior — requires [TT-3867], merged 2026-08-31). `task done ≡ PR merged`
|
||||
still holds, transitively
|
||||
through the batch PR; verify milestones fire unchanged.
|
||||
|
||||
@@ -189,15 +189,15 @@ through the batch PR; verify milestones fire unchanged.
|
||||
Any fallback preserves today's behavior — batch landing is an optimization,
|
||||
never a dependency.
|
||||
|
||||
## Measurement (pilot duty — revised per [org-internal #3731] charter addendum 39347)
|
||||
## Measurement (pilot duty — revised per [TT-3731] charter addendum 39347)
|
||||
|
||||
Per-iteration attribution only; the global 7-day ratio is trend context,
|
||||
never a pass/fail judge (same-window confounders: test-slim [org-internal #3855] /
|
||||
test-dedupe [org-internal #3854] / the pilot's own PRs). On the server,
|
||||
never a pass/fail judge (same-window confounders: test-slim [TT-3855] /
|
||||
test-dedupe [TT-3854] / the pilot's own PRs). On the server,
|
||||
`bun .gitea/scripts/ci-run-stats.ts --days 7 --json /tmp/<slug>-ci-stats.json`
|
||||
(the `--json` flag takes a filename — bare, it is a silent no-op; the human
|
||||
summary still prints). Same methodology as the checklist-merge-gate.yml
|
||||
2026-08-27 note. Record on [org-internal #3731]: (a) this batch iteration's per-workflow
|
||||
2026-08-27 note. Record on [TT-3731]: (a) this batch iteration's per-workflow
|
||||
trigger counts vs a historically similar 1:1 iteration, and (b) one
|
||||
fallback drill (construct a path-overlap group → exit-3 split executed).
|
||||
Baseline, trend only: 2026-08-31, 5,081 runs / TOTAL 2.75x single runner.
|
||||
|
||||
@@ -2,41 +2,41 @@
|
||||
name: project-kickoff
|
||||
description: >
|
||||
Use ONLY when the user asks about project setup, kickoff, or project
|
||||
initialization ("kickoff", "project setup", "椤圭洰鍒濆鍖?, "椤圭洰閰嶇疆").
|
||||
initialization ("kickoff", "project setup", "项目初始化", "项目配置").
|
||||
Provides guidance on the octopus project kickoff workflow: checking readiness,
|
||||
running /kickoff or octopus kickoff, configuring codegraph, and understanding
|
||||
project scaffolding. Do not use for application-level configuration 鈥?
|
||||
project scaffolding. Do not use for application-level configuration —
|
||||
this skill covers the octopus project lifecycle, not user application code.
|
||||
triggers:
|
||||
# High-discrimination phrases only ([org-internal #4525]): bare "setup"/"init"/"閰嶇疆" fire
|
||||
# High-discrimination phrases only ([TT-4525]): bare "setup"/"init"/"配置" fire
|
||||
# on any configuration mention, and the skill gate folds the previous
|
||||
# assistant turn on approval turns 鈥?one stray "閰嶇疆" in a reply re-fires
|
||||
# assistant turn on approval turns — one stray "配置" in a reply re-fires
|
||||
# the gate every turn. Keep triggers to phrases that name THIS workflow;
|
||||
# generic setup/init questions still route via the description in the
|
||||
# skills listing.
|
||||
- kickoff
|
||||
- project setup
|
||||
- 椤圭洰鍒濆鍖?
|
||||
- 椤圭洰閰嶇疆
|
||||
- 项目初始化
|
||||
- 项目配置
|
||||
role: Producer
|
||||
---
|
||||
|
||||
> Core 涓珛鐗堬紙Increment 6a 鏀瑰啓锛屽師 deferHard verbatimDir锛夈€傛満鍒躲€佺粨鏋勪笌 frontmatter 淇濇寔锛涘疄渚嬫湳璇紙宸ュ叿鍚嶃€佽矾寰勩€佸伐鍗曞彿锛夋寜 `core/adapters/TERMINOLOGY.md` 缁戝畾鍒板叿浣撳疄渚嬨€?
|
||||
> Core 中立版(Increment 6a 改写,原 deferHard verbatimDir)。机制、结构与 frontmatter 保持;实例术语(工具名、路径、工单号)按 `core/adapters/TERMINOLOGY.md` 绑定到具体实例。
|
||||
# Project Kickoff
|
||||
|
||||
## 1. Overview
|
||||
|
||||
Project kickoff is the octopus project initialization workflow that gets a project from zero to fully configured in one command. It covers readiness detection 鈫?setup 鈫?scaffold 鈫?config 鈫?codegraph init 鈫?skills overlay pull, producing a project that is ready for the full SDLC pipeline without manual configuration steps.
|
||||
Project kickoff is the octopus project initialization workflow that gets a project from zero to fully configured in one command. It covers readiness detection → setup → scaffold → config → codegraph init → skills overlay pull, producing a project that is ready for the full SDLC pipeline without manual configuration steps.
|
||||
|
||||
## 2. When This Skill Activates
|
||||
|
||||
This skill activates when the user's text matches any of the trigger keywords:
|
||||
|
||||
- `kickoff` 鈥?asking about the `/kickoff` command or the kickoff workflow
|
||||
- `project setup` 鈥?asking how to set up a project in octopus
|
||||
- `椤圭洰鍒濆鍖朻 / `椤圭洰閰嶇疆` 鈥?asking how to initialize or configure an octopus project (Chinese)
|
||||
- `kickoff` — asking about the `/kickoff` command or the kickoff workflow
|
||||
- `project setup` — asking how to set up a project in octopus
|
||||
- `项目初始化` / `项目配置` — asking how to initialize or configure an octopus project (Chinese)
|
||||
|
||||
Generic "setup"/"init"/"閰嶇疆" mentions are deliberately NOT triggers ([org-internal #4525]): they collide with everyday configuration talk, and the hard skill gate folds the previous assistant turn into its match text on approval turns 鈥?a passing "鎴栭厤缃?x: false" in a reply would re-fire the gate every turn. `/init` note: `/init` generates AGENTS.md via LLM; kickoff uses the managed template from `octopus setup` 鈥?the Builder distinguishes based on context.
|
||||
Generic "setup"/"init"/"配置" mentions are deliberately NOT triggers ([TT-4525]): they collide with everyday configuration talk, and the hard skill gate folds the previous assistant turn into its match text on approval turns — a passing "或配置x: false" in a reply would re-fire the gate every turn. `/init` note: `/init` generates AGENTS.md via LLM; kickoff uses the managed template from `octopus setup` — the Builder distinguishes based on context.
|
||||
|
||||
Typical user intents include: encountering a readiness prompt at session start, wondering how to initialize a project, or wanting to understand the kickoff workflow steps.
|
||||
|
||||
@@ -57,43 +57,43 @@ ls .gitea/workflows/ .github/workflows/ 2>/dev/null || echo "[GAP: no CI workflo
|
||||
```
|
||||
|
||||
If no workflows exist, recommend creating `.gitea/workflows/ci.yml` (this repo
|
||||
uses Gitea Actions) 鈥?or `.github/workflows/ci.yml` for a GitHub-hosted project
|
||||
鈥?with at minimum: typecheck, lint, and test gates. Without CI, every merge is a
|
||||
manual gate 鈥?type errors, lint regressions, and test failures can land on
|
||||
uses Gitea Actions) — or `.github/workflows/ci.yml` for a GitHub-hosted project
|
||||
— with at minimum: typecheck, lint, and test gates. Without CI, every merge is a
|
||||
manual gate — type errors, lint regressions, and test failures can land on
|
||||
main and go undetected until the next local checkout.
|
||||
|
||||
## 4. Workflow
|
||||
|
||||
The kickoff workflow runs in four automated steps:
|
||||
|
||||
1. **Check readiness** 鈥?Determine if the project needs setup. Run `checkReadinessWithGitea()` or `octopus kickoff --check-only` to inspect the current state.
|
||||
2. **Run kickoff** 鈥?Execute `/kickoff` from the TUI or `octopus kickoff` from the terminal.
|
||||
3. **What happens** 鈥?A Phase 0 gate, then five sequential phases:
|
||||
- Phase 0 鈥?**Gitea auth check**: derives the `gitea` block from the git remote origin (persisting missing fields), then verifies the token (`GET /user`) and runs the auth wizard on failure; never aborts kickoff
|
||||
- [1/5] **Setup** 鈥?Creates project directories and writes `AGENTS.md` from the managed template
|
||||
- [2/5] **Scaffold** 鈥?Creates the `<instance-root>/` skeleton (`core/skills/` directory + default `octopus.jsonc` template if absent); domain skills content arrives via the [5/5] overlay pull
|
||||
- [3/5] **Config stub + MCP wiring** 鈥?Writes the `mcp.codegraph` block into `octopus.jsonc`
|
||||
- [4/5] **Codegraph init** 鈥?Initializes and builds the per-project `.codegraph/` index
|
||||
- [5/5] **Skills remote + overlay pull** 鈥?Opt-in semantics ([org-internal #4370]); branches by flags when no `overlay.remotes` entry is configured:
|
||||
- no flags (interactive run) 鈥?**safe default**: nothing is written; a remediation hint is printed (pass `--skills-remote`, or edit `overlay.remotes`), and the readiness skills item stays not-ready
|
||||
- `--yes` 鈥?legacy behavior kept: writes the default skills remote, then pulls domain skills content (`octopus skills pull` equivalent)
|
||||
- `--skills-remote <owner/repo>` (+ optional `--skills-remote-base-url <url>`) 鈥?writes the specified remote instead (ref `main`; base URL defaults to `<instance-base-url>`), then pulls from it
|
||||
- `overlay.remotes` already configured 鈥?the write is skipped (idempotent; an explicit `--skills-remote` is ignored with a warning)
|
||||
4. **Post-kickoff verification** 鈥?Run `octopus kickoff --check-only` again. After a `--yes` or `--skills-remote` run it reports all 5 items as ready; after a no-flag interactive run it reports 4 of 5 鈥?the skills item stays not-ready until a remote is configured (`--skills-remote`, `--yes`, or a manual `overlay.remotes` edit + `octopus skills pull`).
|
||||
1. **Check readiness** — Determine if the project needs setup. Run `checkReadinessWithGitea()` or `octopus kickoff --check-only` to inspect the current state.
|
||||
2. **Run kickoff** — Execute `/kickoff` from the TUI or `octopus kickoff` from the terminal.
|
||||
3. **What happens** — A Phase 0 gate, then five sequential phases:
|
||||
- Phase 0 — **Gitea auth check**: derives the `gitea` block from the git remote origin (persisting missing fields), then verifies the token (`GET /user`) and runs the auth wizard on failure; never aborts kickoff
|
||||
- [1/5] **Setup** — Creates project directories and writes `AGENTS.md` from the managed template
|
||||
- [2/5] **Scaffold** — Creates the `<instance-root>/` skeleton (`core/skills/` directory + default `octopus.jsonc` template if absent); domain skills content arrives via the [5/5] overlay pull
|
||||
- [3/5] **Config stub + MCP wiring** — Writes the `mcp.codegraph` block into `octopus.jsonc`
|
||||
- [4/5] **Codegraph init** — Initializes and builds the per-project `.codegraph/` index
|
||||
- [5/5] **Skills remote + overlay pull** — Opt-in semantics ([TT-4370]); branches by flags when no `overlay.remotes` entry is configured:
|
||||
- no flags (interactive run) — **safe default**: nothing is written; a remediation hint is printed (pass `--skills-remote`, or edit `overlay.remotes`), and the readiness skills item stays not-ready
|
||||
- `--yes` — legacy behavior kept: writes the default skills remote, then pulls domain skills content (`octopus skills pull` equivalent)
|
||||
- `--skills-remote <owner/repo>` (+ optional `--skills-remote-base-url <url>`) — writes the specified remote instead (ref `main`; base URL defaults to `<instance-base-url>`), then pulls from it
|
||||
- `overlay.remotes` already configured — the write is skipped (idempotent; an explicit `--skills-remote` is ignored with a warning)
|
||||
4. **Post-kickoff verification** — Run `octopus kickoff --check-only` again. After a `--yes` or `--skills-remote` run it reports all 5 items as ready; after a no-flag interactive run it reports 4 of 5 — the skills item stays not-ready until a remote is configured (`--skills-remote`, `--yes`, or a manual `overlay.remotes` edit + `octopus skills pull`).
|
||||
|
||||
### First-ticket hint ([org-internal #3061])
|
||||
### First-ticket hint ([TT-3061])
|
||||
|
||||
For a brand-new project still validating its concept, open the FIRST ticket as
|
||||
`Kind/MVP` 鈥?the interactive no-pipeline mode (decision log + debt register in
|
||||
`Kind/MVP` — the interactive no-pipeline mode (decision log + debt register in
|
||||
the ticket body). It graduates by relabeling to `Kind/Feature` (analyze-dag
|
||||
backfill mode picks up the decision log) when a second session, an external
|
||||
contract, or a second consumer of a shared type appears. Do not route early
|
||||
concept work into the full pipeline "to be safe" 鈥?the pipeline's coordination
|
||||
concept work into the full pipeline "to be safe" — the pipeline's coordination
|
||||
machinery is cost, not quality, at zero coordination.
|
||||
|
||||
## 5. Re-kickoff / Idempotency
|
||||
|
||||
Re-running kickoff on an already-configured project is safe 鈥?every step is idempotent:
|
||||
Re-running kickoff on an already-configured project is safe — every step is idempotent:
|
||||
|
||||
- **Setup** skips existing directories
|
||||
- **Scaffold** skips existing files
|
||||
@@ -107,26 +107,26 @@ Re-running kickoff on an already-configured project is safe 鈥?every step is id
|
||||
|
||||
Common issues and their resolutions:
|
||||
|
||||
- **`codegraph: command not found`** 鈥?Run the `codegraph-setup` skill, or install via `bun add -g @colbymchenry/codegraph`
|
||||
- **Permission denied** 鈥?Check project directory ownership and write permissions
|
||||
- **Partially complete state** 鈥?Re-run `/kickoff`; idempotent steps will complete the missing parts without affecting already-completed steps
|
||||
- **MCP tools not available** 鈥?Verify `mcp.codegraph` exists in `octopus.jsonc`; re-run `octopus kickoff` to write it
|
||||
- **`codegraph: command not found`** — Run the `codegraph-setup` skill, or install via `bun add -g @colbymchenry/codegraph`
|
||||
- **Permission denied** — Check project directory ownership and write permissions
|
||||
- **Partially complete state** — Re-run `/kickoff`; idempotent steps will complete the missing parts without affecting already-completed steps
|
||||
- **MCP tools not available** — Verify `mcp.codegraph` exists in `octopus.jsonc`; re-run `octopus kickoff` to write it
|
||||
|
||||
## 7. Related Commands
|
||||
|
||||
- `/init` 鈥?Generates `AGENTS.md` using an LLM (custom, context-aware); kickoff uses the managed template from `octopus setup`
|
||||
- `octopus setup` 鈥?Creates directories + `AGENTS.md` from the managed template; kickoff calls this internally
|
||||
- `octopus scaffold` 鈥?Creates the `<instance-root>/` skeleton (`core/skills/` directory + default `octopus.jsonc` template if absent); run `octopus skills pull` to fetch domain skills content; kickoff calls this internally
|
||||
- `octopus kickoff --check-only` 鈥?Readiness check only, no pipeline execution
|
||||
- `octopus kickoff --skills-remote <owner/repo>` 鈥?Explicit opt-in: writes the given skills remote to `overlay.remotes` (ref `main`) and pulls it instead of the default
|
||||
- `octopus kickoff --skills-remote-base-url <url>` 鈥?Base URL for `--skills-remote` (requires it); defaults to `<instance-base-url>` when omitted
|
||||
- `octopus kickoff --yes` 鈥?Skips the opt-in confirmation and keeps the legacy behavior of writing the default skills remote (`Octopus/octopus-skills`)
|
||||
- `codegraph-setup` skill 鈥?For installing the codegraph CLI and initializing the per-project index
|
||||
- `/init` — Generates `AGENTS.md` using an LLM (custom, context-aware); kickoff uses the managed template from `octopus setup`
|
||||
- `octopus setup` — Creates directories + `AGENTS.md` from the managed template; kickoff calls this internally
|
||||
- `octopus scaffold` — Creates the `<instance-root>/` skeleton (`core/skills/` directory + default `octopus.jsonc` template if absent); run `octopus skills pull` to fetch domain skills content; kickoff calls this internally
|
||||
- `octopus kickoff --check-only` — Readiness check only, no pipeline execution
|
||||
- `octopus kickoff --skills-remote <owner/repo>` — Explicit opt-in: writes the given skills remote to `overlay.remotes` (ref `main`) and pulls it instead of the default
|
||||
- `octopus kickoff --skills-remote-base-url <url>` — Base URL for `--skills-remote` (requires it); defaults to `<instance-base-url>` when omitted
|
||||
- `octopus kickoff --yes` — Skips the opt-in confirmation and keeps the legacy behavior of writing the default skills remote (`Octopus/octopus-skills`)
|
||||
- `codegraph-setup` skill — For installing the codegraph CLI and initializing the per-project index
|
||||
|
||||
## 8. Reference
|
||||
|
||||
- `<harness-package>/src/project-kickoff/readiness.ts` 鈥?`checkReadiness()` implementation (sync 4-item base)
|
||||
- `<harness-package>/src/project-kickoff/readiness-gitea.ts` 鈥?`checkReadinessWithGitea()` composed 5-item check (adds gitea auth reachable)
|
||||
- `<harness-package>/src/cli/cmd/kickoff.ts` 鈥?`/kickoff` command handler
|
||||
- `core/skills/codegraph-setup/SKILL.md` 鈥?CodeGraph setup skill
|
||||
- Project roadmap at `.artifacts/project-kickoff/` (deprecated 鈥?now stored as wiki page `project-kickoff/roadmap/` via `wiki 璇诲啓 API锛堣 TERMINOLOGY锛塦)
|
||||
- `<harness-package>/src/project-kickoff/readiness.ts` — `checkReadiness()` implementation (sync 4-item base)
|
||||
- `<harness-package>/src/project-kickoff/readiness-gitea.ts` — `checkReadinessWithGitea()` composed 5-item check (adds gitea auth reachable)
|
||||
- `<harness-package>/src/cli/cmd/kickoff.ts` — `/kickoff` command handler
|
||||
- `core/skills/codegraph-setup/SKILL.md` — CodeGraph setup skill
|
||||
- Project roadmap at `.artifacts/project-kickoff/` (deprecated — now stored as wiki page `project-kickoff/roadmap/` via `wiki 读写 API(见 TERMINOLOGY)`)
|
||||
|
||||
+101
-98
@@ -1,25 +1,23 @@
|
||||
---
|
||||
name: release
|
||||
description: >
|
||||
Use ONLY when ready to cut a release. The Release Manager (Worker) inspects
|
||||
Use ONLY when ready to cut a release. The Producer (Worker) inspects
|
||||
project state (git log, version files, build) to determine the semver bump,
|
||||
generate the changelog, tag, and produce a release artifact. Works on any
|
||||
project state 鈥?no pipeline artifacts required.
|
||||
project state — no pipeline artifacts required.
|
||||
triggers:
|
||||
- release
|
||||
- cut release
|
||||
- 鍙戠増
|
||||
- 发版
|
||||
- publish release
|
||||
- ship release
|
||||
role: Producer
|
||||
---
|
||||
|
||||
> Core 涓珛鐗堬紙Increment 6a 鏀瑰啓锛屽師 deferHard verbatimDir锛夈€傛満鍒躲€佺粨鏋勪笌 frontmatter 淇濇寔锛涘疄渚嬫湳璇紙宸ュ叿鍚嶃€佽矾寰勩€佸伐鍗曞彿锛夋寜 `core/adapters/TERMINOLOGY.md` 缁戝畾鍒板叿浣撳疄渚嬨€?
|
||||
# Release
|
||||
|
||||
Prepare and tag a release based on project facts 鈥?git history since the last
|
||||
Prepare and tag a release based on project facts — git history since the last
|
||||
tag, current version, build status, and dependency health. No dependency on `.artifacts/{slug}/`
|
||||
(**deprecated** 鈥?SDLC artifacts now live in the Gitea wiki at `{slug}/...`;
|
||||
(**deprecated** — SDLC artifacts now live in the Gitea wiki at `{slug}/...`;
|
||||
see `_shared/gitea-read-patterns.md`) or any pipeline skill outputs.
|
||||
|
||||
**This SKILL does not deploy.** Deployment is project-specific (K8s, Docker,
|
||||
@@ -28,16 +26,16 @@ produced here is the input to project-specific deployment workflows.
|
||||
|
||||
## Agent Role
|
||||
|
||||
The release is owned and executed by the **Release Manager** (Worker).
|
||||
The release is owned and executed by the **Producer** (Worker).
|
||||
|
||||
**Context compaction**: release is a pipeline stage boundary. The main session
|
||||
compacts at this clean boundary ONLY when a capacity/projection trigger holds,
|
||||
per `core/rules/compact.md` 搂"Stage-boundary compaction" (long multi-stage
|
||||
runs 鈥?DAG Epic orchestration 鈥?keep the legacy every-boundary compaction;
|
||||
short runs 鈥?bugfix / DAG task 鈥?and standalone runs default to NOT
|
||||
compacting). The Release Manager itself is single-phase and
|
||||
per `.octopus/rules/compact.md` §"Stage-boundary compaction" (long multi-stage
|
||||
runs — DAG Epic orchestration — keep the legacy every-boundary compaction;
|
||||
short runs — bugfix / DAG task — and standalone runs default to NOT
|
||||
compacting). The Producer itself is single-phase and
|
||||
artifact-driven (version files, changelog, tag); a mid-run compaction loses
|
||||
nothing 鈥?re-read the release checklist state and git log to resume.
|
||||
nothing — re-read the release checklist state and git log to resume.
|
||||
|
||||
---
|
||||
|
||||
@@ -46,11 +44,11 @@ nothing 鈥?re-read the release checklist state and git log to resume.
|
||||
Before starting the release:
|
||||
|
||||
- [ ] Working tree is clean (`git status` has no uncommitted changes).
|
||||
- [ ] `core/checklists/release.md` is accessible.
|
||||
- [ ] `.octopus/checklists/release.md` is accessible.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 鈥?Pre-release Gate
|
||||
## Phase 1 — Pre-release Gate
|
||||
|
||||
Run each check against the live project. Stop and report failures.
|
||||
|
||||
@@ -65,82 +63,82 @@ Run each check against the live project. Stop and report failures.
|
||||
- No new HIGH or CRITICAL CVEs block the release.
|
||||
- Pre-existing HIGH/CRITICAL CVEs do NOT block but **MUST be filed as
|
||||
tech-debt** before the release lands. File them in TWO TIERS (batching
|
||||
rule, [org-internal #3846] 鈥?a single release audit once fanned out to 14 TDs 鈫?14 PRs 鈫?
|
||||
rule, [TT-3846] — a single release audit once fanned out to 14 TDs → 14 PRs →
|
||||
56-84 CI runs on a saturated runner pool): Tier A below is the general
|
||||
mechanical-change batching rule; Tier B and the escape hatch follow it.
|
||||
|
||||
<a id="phase-1-tier-a"></a>
|
||||
### Tier A 鈥?閫氱敤鏈烘鍙樻洿骞跺崟瑙勫垯 / Universal mechanical-change batching rule
|
||||
### Tier A — 通用机械变更并单规则 / Universal mechanical-change batching rule
|
||||
|
||||
Origin [org-internal #3846] (audit-batch pilot, generalized in place): the rule covers ANY
|
||||
Origin [TT-3846] (audit-batch pilot, generalized in place): the rule covers ANY
|
||||
single-source fan-out of mechanical changes, not just dependency audits.
|
||||
Two source types today: (a) dependency bump audits; (b) docs 鎵归噺淇
|
||||
Two source types today: (a) dependency bump audits; (b) docs 批量修订
|
||||
(batch docs revisions).
|
||||
|
||||
#### 瑙勫垯姝f枃 / Rule text
|
||||
#### 规则正文 / Rule text
|
||||
|
||||
- **Core**: mechanical changes of ONE class fanning out from a single
|
||||
source are filed as ONE batch issue + ONE batch PR 鈥?never N脳issue +
|
||||
N脳PR. The batch body keeps one row per item (per-CVE / per-doc mapping),
|
||||
source are filed as ONE batch issue + ONE batch PR — never N×issue +
|
||||
N×PR. The batch body keeps one row per item (per-CVE / per-doc mapping),
|
||||
so per-item traceability is unchanged; work the batch as a single PR.
|
||||
- **(a) Dependency bump audits** (the [org-internal #3846] origin case): advisories whose
|
||||
- **(a) Dependency bump audits** (the [TT-3846] origin case): advisories whose
|
||||
remediation is a plain version bump (lockfile-only diff, no semver-major
|
||||
jump, no overrides/catalog surgery, no API or adapter fallout) are filed
|
||||
together via `宸ュ崟 API锛堣 TERMINOLOGY锛塩reate` with
|
||||
together via REST `POST .../issues` with
|
||||
`title="[{origin}] audit-batch@{version}: mechanical bumps for {N} advisories (TD-{NNN})"`
|
||||
and labels `[tech_debt_label_id, severity_label_id, kind_bug_label_id]`
|
||||
(severity = highest in the batch). One row per advisory 鈥?CVE/GHSA ID,
|
||||
affected package + from鈫抰o version, severity (CVSS), advisory URL,
|
||||
(severity = highest in the batch). One row per advisory — CVE/GHSA ID,
|
||||
affected package + from→to version, severity (CVSS), advisory URL,
|
||||
recommended remediation, and a per-advisory Reactivation Trigger
|
||||
("resolved when `npm audit` / `bun audit` reports no HIGH/CRITICAL for
|
||||
this advisory") 鈥?so the release-notes `TD-NNN 鈫?#NNNN` mapping stays
|
||||
this advisory") — so the release-notes `TD-NNN → #NNNN` mapping stays
|
||||
per-advisory.
|
||||
- **(b) Docs 鎵归噺淇 (batch docs revisions)**: many small same-class docs
|
||||
- **(b) Docs 批量修订 (batch docs revisions)**: many small same-class docs
|
||||
corrections discovered in one pass (e.g. a terminology sweep) file as ONE
|
||||
issue via the same flow,
|
||||
`title="[{origin}] docs-batch: {class} revisions for {N} files"`, with one
|
||||
row per file (path, correction, reason); same ONE-batch-PR landing.
|
||||
- **Landing**: when members live on separate branches, compose the single
|
||||
batch PR via the `land-batch` skill (`core/skills/land-batch/SKILL.md`
|
||||
鈥?cross-branch batch composition, topology B). For dependency-bump
|
||||
batch PR via the `land-batch` skill (`.octopus/skills/land-batch/SKILL.md`
|
||||
— cross-branch batch composition, topology B). For dependency-bump
|
||||
batches pass `batch-compose --convergent bun.lock` (script
|
||||
`.gitea/scripts/batch-compose.ts`): the regenerable lockfile is exempt
|
||||
from path-overlap admission and lockfile-only conflicts are surgically
|
||||
resolved to the running head's version.
|
||||
|
||||
#### 閫傜敤杈圭晫 / Applicability boundary
|
||||
#### 适用边界 / Applicability boundary
|
||||
|
||||
- **闈?mechanical锛堝惈鍒ゆ柇鎴愬垎鐨勫彉鏇达紝涓嶅苟鍗曪級** 鈥?items requiring judgment
|
||||
- **非 mechanical(含判断成分的变更,不并单)** — items requiring judgment
|
||||
(wording decisions, behavior/API changes, review-dependent edits) are
|
||||
never batched; file each as its own issue.
|
||||
- **璺緞閲嶅彔锛坆atch 鎴愬憳瑙︾鐩稿悓鏂囦欢 鈫?涓嶅苟鍗曪紱鍞竴璞佸厤 =
|
||||
鍙啀鐢熷叡浜枃浠?`bun.lock` 缁?batch-compose `--convergent` 鏀舵暃锛?* 鈥?the sole
|
||||
- **路径重叠(batch 成员触碰相同文件 → 不并单;唯一豁免 =
|
||||
可再生共享文件 `bun.lock` 经 batch-compose `--convergent` 收敛)** — the sole
|
||||
path-overlap exemption is the regenerable shared lockfile under
|
||||
`--convergent`; every other same-file collision stays un-batched.
|
||||
- **semver-major 璺冲彉 / overrides路catalog 鎵嬫湳 / adapter路peer 鑱斿姩锛堚啋
|
||||
Tier B 鐙珛鍗曪紝缁存寔 per-package锛?* 鈥?these stay per-package Tier B
|
||||
- **semver-major 跳变 / overrides·catalog 手术 / adapter·peer 联动(→
|
||||
Tier B 独立单,维持 per-package)** — these stay per-package Tier B
|
||||
issues. Tier B and the escape hatch (below) survive this generalization
|
||||
unchanged.
|
||||
|
||||
#### 闄嶇骇璺緞 / Degradation path
|
||||
#### 降级路径 / Degradation path
|
||||
|
||||
- **骞跺崟 PR CI 澶辫触 鈫?鎸夐攣鏂囦欢 hunk 鎷嗗寘鍥為€€锛坆isect锛?*: for dependency
|
||||
- **并单 PR CI 失败 → 按锁文件 hunk 拆包回退(bisect)**: for dependency
|
||||
batches, bisect by splitting lockfile hunks per package back into
|
||||
per-package PRs 鈥?the original Tier A bisect semantics carried over
|
||||
verbatim (鍚岃涔夛紝娉涘寲鎺緸: every mechanical batch degrades the same way).
|
||||
per-package PRs — the original Tier A bisect semantics carried over
|
||||
verbatim (同语义,泛化措辞: every mechanical batch degrades the same way).
|
||||
- **Docs batches**: split per file back into per-file PRs.
|
||||
- **land-batch composition fallback** (exit codes per
|
||||
`.gitea/scripts/batch-compose.ts`): `3` path-overlap 鈫?split the batch
|
||||
`.gitea/scripts/batch-compose.ts`): `3` path-overlap → split the batch
|
||||
along the reported pairs (or land the overlapping member 1:1) and re-run
|
||||
per group; `4` merge conflict / `5` transport/git error 鈫?fall back to
|
||||
per group; `4` merge conflict / `5` transport/git error → fall back to
|
||||
1:1 PRs for the whole batch.
|
||||
- **Preflight hedge ([org-internal #3846])**: run `bun install --dry-run` before opening
|
||||
a dependency-batch PR 鈥?the resolver accepting the composed version set
|
||||
- **Preflight hedge ([TT-3846])**: run `bun install --dry-run` before opening
|
||||
a dependency-batch PR — the resolver accepting the composed version set
|
||||
is a cheap pre-CI rejection of impossible bump combinations.
|
||||
|
||||
Tier B and the escape hatch (unchanged by the generalization):
|
||||
|
||||
- **Tier B 鈥?surgery, one issue per package**: semver-major jumps,
|
||||
- **Tier B — surgery, one issue per package**: semver-major jumps,
|
||||
adapter/peer fallout, or overrides/catalog surgery keep the
|
||||
per-package issue: `title="[{origin}] {CVE-ID/GHSA-ID} in {package} (TD-{NNN})"`
|
||||
with the same labels; body requirements match the Tier A rows.
|
||||
@@ -148,7 +146,7 @@ Tier B and the escape hatch (unchanged by the generalization):
|
||||
issue when same-day remediation is required (urgent HIGH/CRITICAL).
|
||||
|
||||
De-duplicate against open `tech-debt` issues (match by
|
||||
CVE/GHSA ID) before creating. Record the `TD-NNN 鈫?#NNNN` mapping in the
|
||||
CVE/GHSA ID) before creating. Record the `TD-NNN → #NNNN` mapping in the
|
||||
release notes. See `verify` Phase 5.5 for the tech-debt promotion body
|
||||
template and `_shared/gitea-write-patterns.md` Pattern 3.
|
||||
|
||||
@@ -157,19 +155,19 @@ template and `_shared/gitea-write-patterns.md` Pattern 3.
|
||||
|
||||
| Check | Status |
|
||||
| ----------------- | ----------------------------------------------------- |
|
||||
| Clean workspace | 鉁?/ 鉂? |
|
||||
| Clean workspace | ✅ / ❌ |
|
||||
| Branch | {branch name} |
|
||||
| Build | 鉁?/ 鉂? |
|
||||
| Typecheck + Lint | 鉁?/ 鉂? |
|
||||
| Tests | 鉁?/ 鉂?(N passed, M failed) |
|
||||
| Dependency audit | 鉁?/ 鈿狅笍 N known CVEs (pre-existing) / 鉂?N new CVEs |
|
||||
| Build | ✅ / ❌ |
|
||||
| Typecheck + Lint | ✅ / ❌ |
|
||||
| Tests | ✅ / ❌ (N passed, M failed) |
|
||||
| Dependency audit | ✅ / ⚠️ N known CVEs (pre-existing) / ❌ N new CVEs |
|
||||
```
|
||||
|
||||
If any gate fails except known CVEs, stop and report what failed.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 鈥?Version Bump
|
||||
## Phase 2 — Version Bump
|
||||
|
||||
Determine the new version by inspecting git history since the last tag.
|
||||
|
||||
@@ -193,14 +191,14 @@ Determine the new version by inspecting git history since the last tag.
|
||||
| `docs:` / `chore:` | (skip) | Not user-visible |
|
||||
|
||||
If no conventional prefix found, infer from the subject line:
|
||||
- "add", "implement", "introduce" 鈫?MINOR
|
||||
- "fix", "resolve", "correct" 鈫?PATCH
|
||||
- "remove", "drop", "rename" (public API) 鈫?MAJOR
|
||||
- "add", "implement", "introduce" → MINOR
|
||||
- "fix", "resolve", "correct" → PATCH
|
||||
- "remove", "drop", "rename" (public API) → MAJOR
|
||||
|
||||
5. **Compute bump**:
|
||||
- If any MAJOR commit 鈫?bump MAJOR.
|
||||
- Else if any MINOR commit 鈫?bump MINOR.
|
||||
- Else 鈫?bump PATCH.
|
||||
- If any MAJOR commit → bump MAJOR.
|
||||
- Else if any MINOR commit → bump MINOR.
|
||||
- Else → bump PATCH.
|
||||
|
||||
```markdown
|
||||
## Version Bump
|
||||
@@ -210,12 +208,12 @@ Determine the new version by inspecting git history since the last tag.
|
||||
**New version**: {new version}
|
||||
**Type**: MAJOR / MINOR / PATCH
|
||||
**Commits since last tag**: {N}
|
||||
**Reason**: {justification 鈥?e.g. "2 feat + 3 fix 鈫?MINOR"}
|
||||
**Reason**: {justification — e.g. "2 feat + 3 fix → MINOR"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 3 鈥?Changelog
|
||||
## Phase 3 — Changelog
|
||||
|
||||
Generate the changelog from `git log <last-tag>..HEAD`:
|
||||
|
||||
@@ -224,10 +222,10 @@ Generate the changelog from `git log <last-tag>..HEAD`:
|
||||
- Scope (if present, e.g. `feat(auth):`).
|
||||
- Description (the subject line, past tense, human-readable).
|
||||
2. **Group by type**:
|
||||
- **Added** 鈥?`feat:` commits.
|
||||
- **Changed** 鈥?modifications to existing behavior (non-breaking).
|
||||
- **Fixed** 鈥?`fix:` commits.
|
||||
- **Breaking** 鈥?`BREAKING CHANGE:` or `!:` commits.
|
||||
- **Added** — `feat:` commits.
|
||||
- **Changed** — modifications to existing behavior (non-breaking).
|
||||
- **Fixed** — `fix:` commits.
|
||||
- **Breaking** — `BREAKING CHANGE:` or `!:` commits.
|
||||
3. **Deduplicate**: squash multiple commits for the same change into one entry
|
||||
where it makes narrative sense.
|
||||
4. Read the existing root `CHANGELOG.md` (if any) and prepend this release.
|
||||
@@ -235,7 +233,7 @@ Generate the changelog from `git log <last-tag>..HEAD`:
|
||||
Write to root `CHANGELOG.md` (prepend section).
|
||||
|
||||
```markdown
|
||||
## [{version}] 鈥?{YYYY-MM-DD}
|
||||
## [{version}] — {YYYY-MM-DD}
|
||||
|
||||
### Added
|
||||
|
||||
@@ -251,24 +249,24 @@ Write to root `CHANGELOG.md` (prepend section).
|
||||
|
||||
### Breaking
|
||||
|
||||
- {breaking change} ({hash}) 鈥?see migration notes above
|
||||
- {breaking change} ({hash}) — see migration notes above
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 鈥?Tag & Finalize
|
||||
## Phase 4 — Tag & Finalize
|
||||
|
||||
1. **Update version file** 鈥?write the new version to the project's version
|
||||
1. **Update version file** — write the new version to the project's version
|
||||
manifest.
|
||||
2. **Commit**: `git add` version file + changelog file, commit with message:
|
||||
```
|
||||
release: {version}
|
||||
```
|
||||
3. **Tag**: `git tag v{version}` (adjust prefix per project convention 鈥?
|
||||
3. **Tag**: `git tag v{version}` (adjust prefix per project convention —
|
||||
check existing tags with `git tag -l`).
|
||||
4. **Verify tag**: `git tag -l v{version}` confirms the tag exists.
|
||||
|
||||
**Do not push** 鈥?the user must explicitly request pushing to remote.
|
||||
**Do not push** — the user must explicitly request pushing to remote.
|
||||
|
||||
```markdown
|
||||
## Release Artifact
|
||||
@@ -282,19 +280,19 @@ Write to root `CHANGELOG.md` (prepend section).
|
||||
|
||||
| File | Change |
|
||||
| -------------- | ------------------------- |
|
||||
| {version file} | {old} 鈫?{new} |
|
||||
| {version file} | {old} → {new} |
|
||||
| CHANGELOG.md | Prepended {version} |
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 4b 鈥?Publish Release Artifacts (octopus project, manual)
|
||||
## Phase 4b — Publish Release Artifacts (octopus project, manual)
|
||||
|
||||
> Octopus-specific. Other projects: substitute your own artifact pipeline 鈥?
|
||||
> Octopus-specific. Other projects: substitute your own artifact pipeline —
|
||||
> the goal is identical (turn the tag into downloadable assets).
|
||||
|
||||
The CI publish pipeline (`.gitea/workflows/publish.yml`) was **retired by
|
||||
[org-internal #2003]** (138/138 historical runs cancelled; the pipeline sat unused for 35+
|
||||
[TT-2003]** (138/138 historical runs cancelled; the pipeline sat unused for 35+
|
||||
days). Releasing octopus is now a **manual local process**. All former CI
|
||||
steps live in repo scripts, runnable from a maintainer machine with the right
|
||||
credentials in the environment.
|
||||
@@ -303,17 +301,17 @@ credentials in the environment.
|
||||
|
||||
- Clean checkout of the release commit (tag pushed or about to be pushed).
|
||||
- Credentials in env:
|
||||
- `GITEA_TOKEN` 鈥?PAT with `write:repository` (release create/undraft,
|
||||
- `GITEA_TOKEN` — PAT with `write:repository` (release create/undraft,
|
||||
tag push) and `write:package` (container registry). The `CI_PAT` secret
|
||||
value is the canonical token.
|
||||
- `NODE_AUTH_TOKEN` 鈥?only if publishing to npm.
|
||||
- `AUR_KEY` 鈥?only if pushing the AUR package.
|
||||
- `NODE_AUTH_TOKEN` — only if publishing to npm.
|
||||
- `AUR_KEY` — only if pushing the AUR package.
|
||||
- Docker logged in to the Gitea container registry:
|
||||
`echo "$GITEA_TOKEN" | docker login <instance-registry-host> -u <user> --password-stdin`.
|
||||
`echo "$GITEA_TOKEN" | docker login eightarms.net -u <user> --password-stdin`.
|
||||
|
||||
### Steps
|
||||
|
||||
1. **Version + draft release** (idempotent 鈥?skips if already published):
|
||||
1. **Version + draft release** (idempotent — skips if already published):
|
||||
```bash
|
||||
GITEA_TOKEN=<pat> GH_REPO=Octopus/octopus bun script/version.ts
|
||||
```
|
||||
@@ -323,7 +321,7 @@ credentials in the environment.
|
||||
```bash
|
||||
OCTOPUS_VERSION={version} OCTOPUS_RELEASE={release-id} \
|
||||
GH_REPO=Octopus/octopus GITEA_TOKEN=<pat> \
|
||||
bun <harness-package>/script/build.ts
|
||||
bun packages/octopus/script/build.ts
|
||||
```
|
||||
`build.ts` attaches the 12 release assets to the draft release.
|
||||
|
||||
@@ -339,14 +337,14 @@ credentials in the environment.
|
||||
4. **Undraft the release** (makes it public):
|
||||
```bash
|
||||
curl -fsS -X PATCH \
|
||||
"<instance-base-url>/api/v1/repos/Octopus/octopus/releases/{release-id}" \
|
||||
"https://eightarms.net/api/v1/repos/Octopus/octopus/releases/{release-id}" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" -d '{"draft": false}'
|
||||
```
|
||||
|
||||
5. **Verify assets** 鈥?the release must carry 12 assets:
|
||||
5. **Verify assets** — the release must carry 12 assets:
|
||||
```bash
|
||||
curl -sS "<instance-base-url>/api/v1/repos/Octopus/octopus/releases/tags/v{version}" \
|
||||
curl -sS "https://eightarms.net/api/v1/repos/Octopus/octopus/releases/tags/v{version}" \
|
||||
-H "Authorization: token $GITEA_TOKEN" | jq '.assets | length'
|
||||
```
|
||||
|
||||
@@ -360,26 +358,31 @@ credentials in the environment.
|
||||
### Notes
|
||||
|
||||
- **Windows code-signing** is not provisioned (no Windows runner / Azure
|
||||
Trusted Signing); the CLI ships unsigned, as before ([org-internal #252]).
|
||||
Trusted Signing); the CLI ships unsigned, as before ([TT-252]).
|
||||
- **Rollback**: if a step fails mid-release, the draft release + tag can be
|
||||
deleted and re-run; every script above is idempotent or safely re-runnable.
|
||||
- If a future CI pipeline replaces this manual flow, update this section and
|
||||
reference [org-internal #2003] for the retirement rationale.
|
||||
reference [TT-2003] for the retirement rationale.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5 鈥?Rollback Plan
|
||||
## Phase 5 — Rollback Plan
|
||||
|
||||
Document how to undo this release:
|
||||
|
||||
1. **Git rollback**:
|
||||
- `git tag -d v{version}` (if not yet pushed).
|
||||
- `git revert {commit_hash}` (if already merged).
|
||||
- If the release includes DB migrations, confirm the `down` migration exists.
|
||||
- If the release includes DB migrations, confirm the `down` migration exists
|
||||
**when the project's migration tooling provides one**. This repo's Drizzle
|
||||
convention is forward-only (`migration.sql` + `snapshot.json`, no `down`
|
||||
files) — there, record the reversal plan (manual SQL / restore) or mark the
|
||||
change irreversible instead of waiting on a `down` file that never comes.
|
||||
2. **Data rollback** (if applicable):
|
||||
- For each migration, confirm the `down` migration exists and has been tested.
|
||||
- For each migration, confirm the `down` migration exists and has been tested
|
||||
where the tooling offers one; otherwise document the manual reversal steps.
|
||||
- If the release changes data format without a reversible migration, mark
|
||||
`鈿狅笍 IRREVERSIBLE DATA CHANGE`.
|
||||
`⚠️ IRREVERSIBLE DATA CHANGE`.
|
||||
|
||||
```markdown
|
||||
## Rollback Plan
|
||||
@@ -390,7 +393,7 @@ git tag -d v{version}
|
||||
# or: git revert {hash}
|
||||
|
||||
### Data Rollback
|
||||
- Migration `{name}`: down {exists / NOT FOUND}
|
||||
- Migration `{name}`: down {exists / NOT FOUND / N/A — forward-only tooling}
|
||||
- {additional risks}
|
||||
|
||||
### Rollback Triggers
|
||||
@@ -403,7 +406,7 @@ git tag -d v{version}
|
||||
|
||||
---
|
||||
|
||||
## Phase 6 鈥?Post-release Smoke Test
|
||||
## Phase 6 — Post-release Smoke Test
|
||||
|
||||
1. Run the project's build command on the tagged commit. Must pass.
|
||||
2. Run the test suite. Must pass.
|
||||
@@ -411,15 +414,15 @@ git tag -d v{version}
|
||||
|
||||
---
|
||||
|
||||
## Phase 7 鈥?Report
|
||||
## Phase 7 — Report
|
||||
|
||||
```markdown
|
||||
## Release Report
|
||||
|
||||
**Version**: {old} 鈫?{new} (MAJOR / MINOR / PATCH)
|
||||
**Version**: {old} → {new} (MAJOR / MINOR / PATCH)
|
||||
**Tag**: v{version}
|
||||
**Commits**: {N} since last tag ({feat} features, {fix} fixes)
|
||||
**Typecheck**: 鉁?| Lint: 鉁?| Tests: 鉁?
|
||||
**Typecheck**: ✅ | Lint: ✅ | Tests: ✅
|
||||
|
||||
### Changelog
|
||||
|
||||
@@ -427,21 +430,21 @@ git tag -d v{version}
|
||||
|
||||
### Release Artifacts
|
||||
|
||||
- Commit: {hash} 鈥?`release: {version}`
|
||||
- Commit: {hash} — `release: {version}`
|
||||
- Tag: v{version}
|
||||
- Changelog: CHANGELOG.md updated
|
||||
|
||||
---
|
||||
|
||||
**Deploy**: {manual step 鈥?"merge to main triggers CI", etc.}
|
||||
**Deploy**: {manual step — "merge to main triggers CI", etc.}
|
||||
**Rollback**: see Phase 5 above
|
||||
**Next**: `core/skills/retrospective/SKILL.md` (optional 鈥?run on any project state)
|
||||
**Next**: `.octopus/skills/retrospective/SKILL.md` (optional — run on any project state)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- `core/checklists/release.md` 鈥?Release checklist
|
||||
- `.octopus/checklists/release.md` — Release checklist
|
||||
- Semver spec: https://semver.org
|
||||
- Conventional Commits: https://www.conventionalcommits.org
|
||||
|
||||
@@ -232,7 +232,7 @@ review findings not actionable upstream]`.
|
||||
archive-at-close; (b) the committed archive bundles
|
||||
`<runs-root>/archive/{slug}.json`, where per-review round counts are
|
||||
reconstructed from the documented `reviews/{stage}/round{N}/` layout in
|
||||
`index.artifacts[].path` ([org-internal #2591] — the archive source is what makes M3
|
||||
`index.artifacts[].path` ([TT-2591] — the archive source is what makes M3
|
||||
durable instead of structurally emptying as runs close). Available once
|
||||
any run has closed.
|
||||
- Rework fraction: 🟢 <15% / 🟡 15–30% / 🔴 >30%.
|
||||
@@ -245,7 +245,7 @@ or upstream design unclear]`.
|
||||
- 🟢 cache_read/input > 10:1 / 🟡 3–10:1 / 🔴 < 3:1.
|
||||
- < 3:1 → `[SIGNAL: cache hit <3:1 — context re-read, code-graph-first
|
||||
not followed]`.
|
||||
- **Compact frequency ([org-internal #2601] pilot data)**: report the token-telemetry
|
||||
- **Compact frequency ([TT-2601] pilot data)**: report the token-telemetry
|
||||
"Compactor Activity" line (compactor messages/tokens in window) and the
|
||||
zero-compact share of short runs (bugfix / DAG task) — the capacity-driven compaction
|
||||
pilot metrics. A rising zero-compact share with NO late-stage
|
||||
@@ -259,7 +259,7 @@ not followed]`.
|
||||
- < 1:1 → `[SIGNAL: explore/execute <1:1 — workers doing explorers' job,
|
||||
exploration skipped or under-delegated]`.
|
||||
|
||||
### 2.8 Gate defect-escape analysis (single metric, [org-internal #3061])
|
||||
### 2.8 Gate defect-escape analysis (single metric, [TT-3061])
|
||||
|
||||
Gates earn their cost by what they CATCH, and the honest test is what slips
|
||||
past them: a gate that runs clean while the same defect resurfaces downstream
|
||||
@@ -297,7 +297,7 @@ status` CLI or commit-status inspection. Final reports at
|
||||
downstream sources for an escape.
|
||||
3. Tally per `gate_id`: `clean_runs`, `escapes`, `escape_rate`.
|
||||
4. Reading (thresholds are this skill's own policy — the `gate_trim:` block
|
||||
they once deferred to was retired 2026-08-21, [org-internal #3072] phase 3; nothing
|
||||
they once deferred to was retired 2026-08-21, [TT-3072] phase 3; nothing
|
||||
trims gates anymore, so the trim-candidate branch below is gone):
|
||||
- `escape_rate ≥ 0.3` → the gate is
|
||||
**UNDER-POWERED**: route the escape causes into §2.9 pre-flight
|
||||
@@ -305,12 +305,12 @@ status` CLI or commit-status inspection. Final reports at
|
||||
propose trimming it.
|
||||
- `escape_rate < 0.3` → healthy; report the numbers, no further verdict.
|
||||
|
||||
**DAG single-gate exclusion ([org-internal #2267])**: `review-dag` is structurally
|
||||
**DAG single-gate exclusion ([TT-2267])**: `review-dag` is structurally
|
||||
non-trimmable (`dag.route.single_gate.never_trim: true` — self-contained in
|
||||
the `dag:` block); `verify` and `merge-pr` were `never_trim` in the retired
|
||||
`gate_trim` block and stay untouchable by convention.
|
||||
|
||||
**keep_gates exclusion (TD-390, [org-internal #3061]) — RETIRED with gate_trim**: the
|
||||
**keep_gates exclusion (TD-390, [TT-3061]) — RETIRED with gate_trim**: the
|
||||
rule that a trim candidate's gate must not be a member of the target route's
|
||||
`keep_gates` guarded a landing field (`sizing.tiers.*.additional_skip`)
|
||||
that no longer exists. Historical record: wiki `rules/gate-trim`.
|
||||
@@ -331,10 +331,10 @@ runs for a gate → report the raw numbers with
|
||||
- [NOTE: insufficient sample for gate X] where clean runs < 5.
|
||||
- UNDER-POWERED gates (escape_rate ≥ 0.3) feed §2.9 pre-flight — never a
|
||||
unilateral trim: the only exit is a furlough entry in
|
||||
`<instance-root>/gate-ledger.yaml` (evidence + reopen condition, [org-internal #3607]).
|
||||
`<instance-root>/gate-ledger.yaml` (evidence + reopen condition, [TT-3607]).
|
||||
```
|
||||
|
||||
### 2.9 Pre-flight defect-prevention analysis ([org-internal #2599])
|
||||
### 2.9 Pre-flight defect-prevention analysis ([TT-2599])
|
||||
|
||||
First-round FAIL/WARN findings are the pipeline's cost multiplier: every
|
||||
multi-round review pays for them twice (review round + revision round).
|
||||
@@ -348,13 +348,13 @@ code.
|
||||
reports for the cycle's tickets (`{slug}/reviews/{stage}/final/report` —
|
||||
round-1 findings with severity FAIL/WARN, their dimension codes, and the
|
||||
finding text for root-cause categorization) + the source issues'
|
||||
`Kind/*` labels. For DAG-routed Epics ([org-internal #2905] 方案 3), two further
|
||||
`Kind/*` labels. For DAG-routed Epics ([TT-2905] 方案 3), two further
|
||||
read-only sources feed the `REQ × late-discovery` root cause (step 1):
|
||||
(a) **DAG oversize-signal events** — `node_split` / registry-row additions
|
||||
recorded on the Epic's issue timeline / `## DAG 状态` whose trigger is a NEW
|
||||
requirement rather than a refactor; (b) **demo-period feedback** —
|
||||
stakeholder comments naming functionality the frozen DAG never covered. For browser-evidence
|
||||
cycles ([org-internal #4499], contract `browser-evidence-4486/shared/evidence-ref-v1` §3), a
|
||||
cycles ([TT-4499], contract `browser-evidence-4486/shared/evidence-ref-v1` §3), a
|
||||
third read-only
|
||||
source: (c) **browser session rows** — per browser-debug session
|
||||
`{session_id, outcome: evidence-captured | env-unavailable | replay-failed,
|
||||
@@ -373,7 +373,7 @@ Rows are currently Task-DAG cycle products by default (the helper's
|
||||
Bug- or Feature-cycle session to its own landing slot). The replay
|
||||
success-rate baseline (N-03 BENCH) is exposed as a consumable metric — a SEEDED CONVENTION (fixture-authored outcomes, channel health),
|
||||
NOT a live-browser trend baseline. Mechanical helper:
|
||||
`<harness-package>/scripts/browser-retro-tally.ts`. Boundary rules ([org-internal #4499]
|
||||
`<harness-package>/scripts/browser-retro-tally.ts`. Boundary rules ([TT-4499]
|
||||
AC-3): out-of-enum or empty categories fall into an explicit `other` bucket
|
||||
with provenance (recorded, never silently swallowed, never a crash); rows
|
||||
missing replay/attribution fields yield structured errors in the tally
|
||||
@@ -395,10 +395,10 @@ late-discovery` — 冻结后才被发现的需求 (a requirement that surfaced
|
||||
oversize signal or demo comment — count it from sources (a)/(b) above,
|
||||
not only from review findings.
|
||||
2. Tally per **route-class** — `Bug`, `Feature-DAG`, `Epic-DAG-route`,
|
||||
`Task-DAG` (Kind/Feature routes to the DAG pipeline since [org-internal #3061] Phase 2 /
|
||||
`Task-DAG` (Kind/Feature routes to the DAG pipeline since [TT-3061] Phase 2 /
|
||||
TD-388 — `Feature-legacy` survives only as a historical bucket for tickets
|
||||
closed before 2026-08-20; the Size dimension is retired from retro keying,
|
||||
[org-internal #3061]: DAG-routed tickets derive depth instead of carrying `Size/*`
|
||||
[TT-3061]: DAG-routed tickets derive depth instead of carrying `Size/*`
|
||||
(spec-06), and `Kind/Bug` carries no ladder). First-round hit count
|
||||
and distinct-ticket count per cause per class.
|
||||
3. A cause is a **pre-flight candidate** when ALL hold (thresholds from
|
||||
@@ -408,7 +408,7 @@ late-discovery` — 冻结后才被发现的需求 (a requirement that surfaced
|
||||
A qualifying `Epic × DAG-route` cause (e.g. `REQ × late-discovery`) lands
|
||||
on `<instance-root>/workflow-routing.yaml` `dag.route.preflight` — NOT
|
||||
`routes.Kind/Epic.preflight` (legacy-roadmap-era landing; the legacy route
|
||||
was archived [org-internal #3072] phase 3) ([org-internal #2905] 方案 3). The analyze-dag skill reads
|
||||
was archived [TT-3072] phase 3) ([TT-2905] 方案 3). The analyze-dag skill reads
|
||||
`dag.route.preflight` before decomposition.
|
||||
4. Aging: for causes ALREADY landed in `routes.{Kind}.preflight` or
|
||||
`dag.route.preflight`, count
|
||||
@@ -423,7 +423,7 @@ Sample-sufficiency guard mirrors 2.8: zero qualifying tickets → emit
|
||||
|
||||
| route-class | Cause (checklist-qualified dim × root-cause) | 1st-round hits | tickets | qualify? |
|
||||
| -------------- | ------------------------------------------- | -------------- | --------------------------- | -------------------------------- |
|
||||
| Bug | code-review.md COR × unhandled-null | 5 | 4 ([org-internal #2400] [org-internal #2429] [org-internal #2471] [org-internal #2488]) | ✅ PROPOSE |
|
||||
| Bug | code-review.md COR × unhandled-null | 5 | 4 ([TT-2400] [TT-2429] [TT-2471] [TT-2488]) | ✅ PROPOSE |
|
||||
| Bug | code-review.md STY × wrong-import-order | 6 | 2 | ⛔ tickets <3 |
|
||||
| Feature-DAG | code-review.md TST × missing-boundary-test | 3 | 3 | ⛔ hits <5 |
|
||||
| Epic-DAG-route | REQ × late-discovery | 5 | 3 (#27xx #28xx #29xx) | ✅ PROPOSE → dag.route.preflight |
|
||||
@@ -433,7 +433,7 @@ Sample-sufficiency guard mirrors 2.8: zero qualifying tickets → emit
|
||||
- Landed-item aging: `cor-unhandled-null clean streak 5 ≥ aging 5` → REMOVAL row.
|
||||
```
|
||||
|
||||
### 2.10 Derived-ticket health ([org-internal #3061])
|
||||
### 2.10 Derived-ticket health ([TT-3061])
|
||||
|
||||
Derived tickets (TD promotions, BF umbrellas, FT tickets) are the pipeline's
|
||||
exhaust. Unmanaged they accumulate into flush cycles (2026-08 evidence: 122
|
||||
@@ -477,7 +477,7 @@ this probe checks whether the system DIGESTS what it records:
|
||||
- rows marked [COLD] this cycle: {list or "none"}
|
||||
```
|
||||
|
||||
### 2.11 Threshold calibration tally ([org-internal #3380])
|
||||
### 2.11 Threshold calibration tally ([TT-3380])
|
||||
|
||||
Process prose constants (round caps, D1–D4 thresholds, preflight knobs,
|
||||
escape-rate cutoffs, quotas — full index:
|
||||
@@ -665,7 +665,7 @@ Each item MUST specify:
|
||||
- Action items that modify SKILLs or templates are applied immediately (the
|
||||
Retrospective Lead can edit `<instance-root>/` files).
|
||||
- Action items MUST NOT be vague ("try harder", "be more careful").
|
||||
- **Layering question** (injection-budget ruling item 3, [org-internal #3547]): every action
|
||||
- **Layering question** (injection-budget ruling item 3, [TT-3547]): every action
|
||||
item that encodes a lesson as a process constraint MUST answer **"which
|
||||
layer carries this lesson?"** — options in ascending per-turn cost, pick
|
||||
the cheapest that actually enforces it:
|
||||
@@ -682,7 +682,7 @@ Each item MUST specify:
|
||||
corpus — do not casually re-grow it; the rule-GC report in that same check
|
||||
flags aging L1 rules for L2 retirement).
|
||||
|
||||
**TRIM PROPOSAL rows — RETIRED ([org-internal #3072] phase 3, 2026-08-21)**: the
|
||||
**TRIM PROPOSAL rows — RETIRED ([TT-3072] phase 3, 2026-08-21)**: the
|
||||
gate-trim landing machinery (`gate_trim.action` →
|
||||
`sizing.tiers.{Size}.additional_skip` / `routes.{Kind}.skip` /
|
||||
`auto_approve.stages`) was removed with the `gate_trim:` and `sizing:`
|
||||
@@ -691,12 +691,12 @@ Gate health findings flow exclusively through §2.8's escape-rate verdict
|
||||
(UNDER-POWERED → §2.9 pre-flight) and ordinary action items. Historical
|
||||
spec: wiki `rules/gate-trim` (L2).
|
||||
|
||||
**PRE-FLIGHT PROPOSAL rows** (from Phase 2.9 defect-prevention, [org-internal #2599]): format
|
||||
**PRE-FLIGHT PROPOSAL rows** (from Phase 2.9 defect-prevention, [TT-2599]): format
|
||||
the What cell as
|
||||
`Add pre-flight '{id}' to {Kind} ({hits} first-round FAIL/WARN hits, {tickets} tickets — {evidence})`
|
||||
and the Where cell as
|
||||
`<instance-root>/workflow-routing.yaml` `routes.{Kind}.preflight` — or, for causes
|
||||
keyed `Epic × DAG-route` (e.g. `REQ × late-discovery`, [org-internal #2905] 方案 3),
|
||||
keyed `Epic × DAG-route` (e.g. `REQ × late-discovery`, [TT-2905] 方案 3),
|
||||
`<instance-root>/workflow-routing.yaml` `dag.route.preflight` (consumed by
|
||||
analyze-dag before decomposition).
|
||||
Aging removal rows: `Remove pre-flight '{id}' from {Kind} (clean streak {N} ≥ aging threshold)`.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: review-artifact
|
||||
description: >-
|
||||
Use ONLY after analyze-dag has produced the DAG artifact — review the task DAG (review-dag single gate) — OR when auditing the <instance-root>/ process infrastructure itself (audit-process). Spawns N parallel Explorer reviewers (1 dimension each) against the matching checklist, synthesizes findings with a Worker Synthesizer, and iterates with a Worker reviser until convergence. The legacy roadmap / design-space / iteration-plan targets were archived 2026-08-21 ([org-internal #3072] phase 3, <instance-root>/archive/). Do NOT use for code review — use the review-code skill for that.
|
||||
Use ONLY after analyze-dag has produced the DAG artifact — review the task DAG (review-dag single gate) — OR when auditing the <instance-root>/ process infrastructure itself (audit-process). Spawns N parallel Explorer reviewers (1 dimension each) against the matching checklist, synthesizes findings with a Worker Synthesizer, and iterates with a Worker reviser until convergence. The legacy roadmap / design-space / iteration-plan targets were archived 2026-08-21 ([TT-3072] phase 3, <instance-root>/archive/). Do NOT use for code review — use the review-code skill for that.
|
||||
triggers:
|
||||
- audit-process
|
||||
- review-dag
|
||||
@@ -25,19 +25,22 @@ role: Reviewer
|
||||
## Tool Availability & Path Resolution
|
||||
|
||||
This skill's reviewers (parallel Explorer subagents) read two kinds of files.
|
||||
Some runs lack the `gitea_wiki__*` MCP tools (cross-repo scenario, [org-internal #2115]); the
|
||||
fallbacks below keep reviews working without them.
|
||||
Some runs cannot reach the Gitea REST API (cross-repo scenario, [TT-2115]); the
|
||||
fallbacks below keep reviews working without it.
|
||||
|
||||
The Orchestrator probes availability **before dispatching reviewers** (Phase A
|
||||
The Orchestrator probes REST reachability **before dispatching reviewers** (Phase A
|
||||
step 1, `_shared/review-pipeline-phases.md`) and fails fast if neither path is
|
||||
usable, so every reviewer has a working read path by the time it runs.
|
||||
|
||||
### Wiki artifacts (DAG artifact / review reports)
|
||||
|
||||
- **Primary**: `wiki 读写 API(见 TERMINOLOGY)(owner, repo, page_name)` — use when the
|
||||
tool is available. `page_name` construction is in
|
||||
- **Primary**: `GET <gitea-base-url>/api/v1/repos/{owner}/{repo}/wiki/page/{mangled-name}`
|
||||
— use when REST is reachable. Resolve `{mangled-name}` from
|
||||
`GET .../wiki/pages` (`sub_url` — mangled name with `%2F` encoding and
|
||||
possible `.-` suffix); never construct it by hand. Page-name resolution
|
||||
context is in
|
||||
`_shared/gitea-read-patterns.md` Pattern 1.
|
||||
- **Fallback** (when `gitea_wiki__*` is unavailable): read the **local wiki
|
||||
- **Fallback** (when REST is unreachable): read the **local wiki
|
||||
clone** at `<wiki-clone-root>/{repo}-wiki/` — a git checkout of the wiki repo,
|
||||
kept current. Wiki filenames are URL-encoded (`/` → `%2F`, with a possible
|
||||
`.-` before `.md`), so resolve the file with `glob` rather than constructing
|
||||
@@ -71,7 +74,7 @@ This skill reviews different artifact types. Identify the target from the pipeli
|
||||
| **review-dag** | `review-dag` | `core/checklists/dag-single-gate.md` | 3 | Analyst | `{epic-slug}/reviews/review-dag/` |
|
||||
|
||||
> **Retired targets (historical)**: the `roadmap`, `design-space`, and `plan`
|
||||
> targets were archived on 2026-08-21 per [org-internal #3072] phase 3 (ruling:
|
||||
> targets were archived on 2026-08-21 per [TT-3072] phase 3 (ruling:
|
||||
> `docs/workflow-refactor/phase3-retirement-ruling.md`) — the legacy
|
||||
> production skills they gated no longer exist (see `<instance-root>/archive/`).
|
||||
> Their stage ids (`review-roadmap`, `review-design-space`,
|
||||
@@ -81,7 +84,7 @@ This skill reviews different artifact types. Identify the target from the pipeli
|
||||
|
||||
The stage IDs remain as-is — they are used by the stage registry and auto-approve system. The skill name is `review-artifact`, but the stage IDs do not change.
|
||||
|
||||
> **Progressive disclosure ([org-internal #3734])**: this skill has two disjoint live
|
||||
> **Progressive disclosure ([TT-3734])**: this skill has two disjoint live
|
||||
> targets — dispatch an auditor/reviewer with
|
||||
> `skills: ["review-artifact:target-process"]` or
|
||||
> `["review-artifact:target-review-dag"]` (preamble + that target only)
|
||||
@@ -145,7 +148,7 @@ Before launching any review, confirm:
|
||||
|
||||
Each target adds specific preconditions listed in its section below. If any precondition is unmet, abort and inform the user.
|
||||
|
||||
> ## Retired targets (historical, [org-internal #3072] phase 3)
|
||||
> ## Retired targets (historical, [TT-3072] phase 3)
|
||||
|
||||
The three legacy production-review targets — **roadmap** (stage
|
||||
`review-roadmap`, checklist `roadmap.md`, revision role Analyst),
|
||||
@@ -184,6 +187,15 @@ The audit target is the **SDLC factory itself** — the set of skills, checklist
|
||||
- [ ] `core/skills/` exists and contains at least one `SKILL.md`.
|
||||
- [ ] `core/checklists/audit-process.md` is accessible.
|
||||
- [ ] `core/schemas/` contains the shared review schemas (`reviewer-output`, `synthesis`, `review-status`).
|
||||
- [ ] **Process-tests-green gate ([TT-4787] STD 8.8)**: before dispatching
|
||||
auditors, the Orchestrator (bash-capable; Explorer auditors have none by
|
||||
construction) runs the process's own suite and guards — from
|
||||
`<harness-package>`: `bun run test:parallel`, plus the repo-root `check:*`
|
||||
guard family — and writes the commands, baseline SHA, and per-command result
|
||||
summary to `<runs-root>/audit/reviews/audit-process/process-tests-green.md`
|
||||
(Tier 1). The read-only STD 8.8 auditor verifies that record against the
|
||||
current baseline; any red test/guard is itself a process defect and MUST be
|
||||
filed as a finding.
|
||||
|
||||
No `.artifacts/{slug}/` inputs are required — the audit reads `<instance-root>/` itself. Audit outputs are published as Gitea wiki pages under `audit/{date}/`.
|
||||
|
||||
@@ -198,7 +210,7 @@ No `.artifacts/{slug}/` inputs are required — the audit reads `<instance-root>
|
||||
| 5 | FLOW | Pipeline Cohesion | FLOW 5.1–5.6 | Preconditions + output sections of every `SKILL.md` |
|
||||
| 6 | SCH | Schema Contract | SCH 6.1–6.5 | `core/schemas/*.json` + skills that reference them |
|
||||
| 7 | DUP | Duplication & Drift | DUP 7.1–7.4 | ALL `SKILL.md` + ALL `checklists/*.md` |
|
||||
| 8 | STD | Audit Standards (ISO/IEEE) | STD 8.1–8.7 | `review-*` skills, `review-artifact` (target: `audit-process`) itself |
|
||||
| 8 | STD | Audit Standards (ISO/IEEE) | STD 8.1–8.8 | `review-*` skills, `review-artifact` (target: `audit-process`) itself |
|
||||
| 9 | AGT | AGENTS.md Conformance | AGT 9.1–9.5 | ALL `SKILL.md` + `AGENTS.md` |
|
||||
| 10 | TRC | Traceability | TRC 10.1–10.5 | `review-*` skills, schemas, status artifacts |
|
||||
|
||||
@@ -354,9 +366,9 @@ from `Size/*` labels.
|
||||
| D1 | 1 | `all` |
|
||||
| D2 | 3 | `TOPO:1 REQMAP:1 RELEASE:1` |
|
||||
| D3 | 5 | `TOPO:2 REQMAP:2 RELEASE:1` |
|
||||
| D4 | 5 ([org-internal #3061] cap) | `TOPO:2 REQMAP:2 RELEASE:1` |
|
||||
| D4 | 5 ([TT-3061] cap) | `TOPO:2 REQMAP:2 RELEASE:1` |
|
||||
|
||||
> **D4 cap ([org-internal #3061])**: D4 keeps its own rounds budget (4) but its fanout is
|
||||
> **D4 cap ([TT-3061])**: D4 keeps its own rounds budget (4) but its fanout is
|
||||
> capped at D3 level (5 reviewers) — under the 3-dimension + checklist-bound
|
||||
> review the marginal coverage of 9 reviewers was redundancy, and round
|
||||
> iteration is the backstop.
|
||||
@@ -378,7 +390,7 @@ file (concurrent write race):
|
||||
`core/schemas/reviewer-output.schema.json`. Finding ids inside slot
|
||||
files MUST be slot-prefixed (`{DIM}R{k}-F{NNN}`, e.g. `TOPOR1-F001`) so ids
|
||||
stay unique across a dimension's slot files. This preserves per-reviewer
|
||||
attribution (retrospective overlap analysis, [org-internal #2996] step ①a) and makes the
|
||||
attribution (retrospective overlap analysis, [TT-2996] step ①a) and makes the
|
||||
write race impossible by construction.
|
||||
- Synthesis input for a dimension = ALL `findings-{DIM}*.json` in the round
|
||||
directory — the synthesizer already globs every `findings-*.json`; the slot
|
||||
@@ -393,7 +405,7 @@ file (concurrent write race):
|
||||
- `{BASELINE_SECTION}`:
|
||||
```
|
||||
## Baseline
|
||||
The artifact under review is the DAG at wiki page `{epic-slug}/dag` (read via `gitea_wiki__get_page`). Read it first for orientation. Its `dag_metrics.review_depth` (D1–D4) sets this review's depth and round cap.
|
||||
The artifact under review is the DAG at wiki page `{epic-slug}/dag` (read via `GET <gitea-base-url>/api/v1/repos/{owner}/{repo}/wiki/page/{mangled-name}`, `sub_url` resolved from `GET .../wiki/pages` first). Read it first for orientation. Its `dag_metrics.review_depth` (D1–D4) sets this review's depth and round cap.
|
||||
```
|
||||
- `{READ_FIRST_STEPS}`:
|
||||
1. Read the DAG artifact at `{epic-slug}/dag` first for orientation.
|
||||
|
||||
@@ -5,7 +5,7 @@ description: >
|
||||
ticket under a DAG-routed parent) against the node spec + frozen
|
||||
cross-session contracts of the frozen DAG copy (`{epic-slug}/dag`), or in
|
||||
standalone-bugfix mode without a design baseline. (The legacy
|
||||
approved-design pipeline mode was archived 2026-08-21, [org-internal #3072] phase 3.) Spawns up to 10 parallel Explorer reviewers (risk-tier scaled;
|
||||
approved-design pipeline mode was archived 2026-08-21, [TT-3072] phase 3.) Spawns up to 10 parallel Explorer reviewers (risk-tier scaled;
|
||||
fewer in standalone-bugfix mode where DGN may be skipped) against core/checklists/code-review.md, synthesizes
|
||||
findings with a Worker Synthesizer (the main-session Orchestrator aggregates), and iterates with a Worker developer until
|
||||
convergence.
|
||||
@@ -57,7 +57,7 @@ abstract best practices.
|
||||
|
||||
Before launching this review, confirm:
|
||||
|
||||
> **Legacy pipeline preconditions retired ([org-internal #3072] phase 3, 2026-08-21)**: the
|
||||
> **Legacy pipeline preconditions retired ([TT-3072] phase 3, 2026-08-21)**: the
|
||||
> design-document / design-space-convergence / iteration-plan-convergence
|
||||
> checks that used to head this list belonged to the archived legacy pipeline
|
||||
> (`design` / `plan-iterations` skills — `<instance-root>/archive/`). Live entry
|
||||
@@ -66,7 +66,7 @@ Before launching this review, confirm:
|
||||
> runs' design pages stay readable via `_shared/gitea-read-patterns.md`.
|
||||
|
||||
- [ ] Code files to review are specified (list of file paths or use `git diff`).
|
||||
- [ ] Mechanical-green gate PASSED (L0-enforced, [org-internal #2598]): run
|
||||
- [ ] Mechanical-green gate PASSED (L0-enforced, [TT-2598]): run
|
||||
`bun core/skills/review-code/scripts/precondition-gate.ts {slug}` —
|
||||
CI-aligned checks (`bun oxlint --deny-warnings` + `bun turbo typecheck`
|
||||
+ `test:changed` with `CI=true TEST_SHARDS=3`, mirroring ci.yml).
|
||||
@@ -83,7 +83,7 @@ Before launching this review, confirm:
|
||||
- [ ] 跨阶段门控清单: `core/checklists/pipeline-gate.md` is accessible and
|
||||
its Upstream Review Convergence section has been confirmed item by item.
|
||||
|
||||
**Kind/MVP graduation chokepoint ([org-internal #3061])**: when this skill is invoked ad hoc
|
||||
**Kind/MVP graduation chokepoint ([TT-3061])**: when this skill is invoked ad hoc
|
||||
on a `Kind/MVP` ticket's changes (no mode, no pipeline), the mechanical-green
|
||||
gate applies, and the Orchestrator additionally checks the diff for
|
||||
**graduation triggers** — changes crossing ≥2 modules, touching a shared
|
||||
@@ -110,9 +110,9 @@ no design doc exists at `.artifacts/{slug}/design/index.md`(存量只读,不
|
||||
|
||||
**Weakened preconditions** for standalone mode:
|
||||
|
||||
- Design doc existence → NOT required (the legacy design pipeline is archived, [org-internal #3072] phase 3).
|
||||
- Design doc existence → NOT required (the legacy design pipeline is archived, [TT-3072] phase 3).
|
||||
- **Instead require**: `.artifacts/{slug}/repro-notes.md`(存量只读,不迁移;Gitea 等效:wiki page `{slug}/repro-notes`,`_shared/gitea-read-patterns.md` Pattern 1)exists (bugfix Phase 1-2 output: reproduction steps + root cause) OR `.artifacts/{slug}/impl-notes.md`(存量只读,不迁移;Gitea 等效:wiki page `{slug}/impl-notes`,`_shared/gitea-read-patterns.md` Pattern 1)exists (post-fix behavior contract).
|
||||
- All other Preconditions (code files specified, mechanical-green gate green ([org-internal #2598]), checklist accessible) STILL APPLY.
|
||||
- All other Preconditions (code files specified, mechanical-green gate green ([TT-2598]), checklist accessible) STILL APPLY.
|
||||
- The `core/checklists/pipeline-gate.md` cross-stage gate (Upstream Review Convergence section) → NOT required; the bugfix-specific Pre-Design Falsification Gate section still applies if relevant.
|
||||
|
||||
**DGN dimension handling**: In standalone-bugfix mode, the DGN (Design Compliance & Dependencies) reviewer is SKIPPED because there is no design to comply with. The Orchestrator dispatches 9 reviewers (all 10 dimensions except DGN).
|
||||
@@ -120,7 +120,7 @@ no design doc exists at `.artifacts/{slug}/design/index.md`(存量只读,不
|
||||
**What standalone bugfix review focuses on**: code correctness, error handling & compatibility (COR), regression coverage (TST), security (SEC), performance (PERF), style & conventions (STY), database & data (DBT), accessibility & browser compatibility (A11Y), documentation (DOC), traceability (TRC) — everything that does not depend on a design baseline.
|
||||
|
||||
**Historical**: the legacy pipeline mode (design doc + design-space/plan
|
||||
review convergence as preconditions) was archived 2026-08-21 ([org-internal #3072] phase 3).
|
||||
review convergence as preconditions) was archived 2026-08-21 ([TT-3072] phase 3).
|
||||
Historical design pages remain readable via `_shared/gitea-read-patterns.md`.
|
||||
|
||||
### DAG Task Mode
|
||||
@@ -147,7 +147,7 @@ table and implement's §"DAG-mode input path"):
|
||||
| Iteration-plan review converged (`--stage iteration-plan`) | REMOVED (DAG has no plan review; the single review-dag gate replaces both) |
|
||||
| `slug` matches the design slug | N/A (review is scoped to the node ticket; run slug = `{epic-slug}-task-{node-id}` — the same node-task run namespace verify's task mode archives to — so review outputs are node-scoped and never clobber sibling nodes' reports. Note: this namespace covers review + verify runs only; the node's implement report below lives in the Epic run workspace `{epic-slug}/workers/` — implement worker runs keep the Epic run slug (implement §Preconditions: "DAG: `{epic-slug}`"), a different run from this review run) |
|
||||
| `core/checklists/pipeline-gate.md` Upstream Review Convergence | NOT required — the review-dag convergence check above stands in its place |
|
||||
| All other preconditions (code files specified, mechanical-green gate green ([org-internal #2598]), checklist accessible) | KEEP — unconditional; plus the implement report (AC → test traceability) present — Tier 1 at `<runs-root>/{epic-slug}/workers/{node-id}-worker-{seq}.md` (implement Phase 5 persistence; `{chunk-id}` = the node id) |
|
||||
| All other preconditions (code files specified, mechanical-green gate green ([TT-2598]), checklist accessible) | KEEP — unconditional; plus the implement report (AC → test traceability) present — Tier 1 at `<runs-root>/{epic-slug}/workers/{node-id}-worker-{seq}.md` (implement Phase 5 persistence; `{chunk-id}` = the node id) |
|
||||
|
||||
The `{BASELINE_SECTION}` for DAG-task mode uses the node spec + cross-session
|
||||
edge contracts from `{epic-slug}/dag` instead of the design index; the 5-Check
|
||||
@@ -228,7 +228,7 @@ file is a test file.
|
||||
- Design-space review convergence → NOT required.
|
||||
- Iteration-plan review convergence → NOT required.
|
||||
- All Preconditions from the pipeline checklist are bypassed.
|
||||
- Only requires: the mechanical-green gate ([org-internal #2598]) — same script as the full
|
||||
- Only requires: the mechanical-green gate ([TT-2598]) — same script as the full
|
||||
mode; on a test-only changeset `test:changed` selects exactly the changed
|
||||
tests, so the gate cost stays proportional to the diff.
|
||||
|
||||
@@ -263,7 +263,7 @@ fall back to the appropriate full mode (pipeline or standalone-bugfix).
|
||||
|
||||
## Agent Roles
|
||||
|
||||
> **Progressive disclosure ([org-internal #3722])**: when dispatching a Reviewer /
|
||||
> **Progressive disclosure ([TT-3722])**: when dispatching a Reviewer /
|
||||
> Synthesizer / Developer scoped to one phase, pass
|
||||
> `skills: ["review-code:phase-a"]` (preamble — incl. dimensions, JSON
|
||||
> schema, prompt template — plus that phase only) instead of the full body;
|
||||
@@ -338,7 +338,7 @@ audit (`review-artifact` targets):
|
||||
| `core/schemas/synthesis.schema.json` | Orchestrator round synthesis (Tier 2 — synthesis comment) |
|
||||
| `core/schemas/review-status.schema.json` | Review lifecycle tracking |
|
||||
|
||||
> **Findings sink: `tier1-local`** ([org-internal #1988]). `review-code` writes raw
|
||||
> **Findings sink: `tier1-local`** ([TT-1988]). `review-code` writes raw
|
||||
> per-dimension findings to Tier 1 local files (`<runs-root>/{slug}/reviews/code/`),
|
||||
> not Gitea issue comments. The synthesis comment + commit status stay Tier 2.
|
||||
> See `_shared/review-pipeline-phases.md` "Output model — two findings sinks"
|
||||
@@ -362,7 +362,7 @@ table).
|
||||
- `{REVIEWER_ROLE}`: code reviewer
|
||||
- `{BASELINE_SECTION}`:
|
||||
|
||||
**Legacy pipeline mode** (archived 2026-08-21, [org-internal #3072] phase 3 — the design
|
||||
**Legacy pipeline mode** (archived 2026-08-21, [TT-3072] phase 3 — the design
|
||||
doc at `{slug}/03-design-*` / `{slug}/02-03-req-design` it read is
|
||||
historical; live modes use the two baselines below):
|
||||
|
||||
@@ -464,7 +464,7 @@ table).
|
||||
|
||||
When invoked from the `implement` skill in bugfix mode (caller passes
|
||||
`mode: "standalone-bugfix"` — the legacy "detect absence of a design doc"
|
||||
fallback is retired with the design pipeline, [org-internal #3072] phase 3):
|
||||
fallback is retired with the design pipeline, [TT-3072] phase 3):
|
||||
|
||||
1. The Orchestrator dispatches **9 reviewers** (all 10 dimensions **except DGN** — Design Compliance & Dependencies), because there is no design baseline to audit compliance against.
|
||||
2. For any dimension that would normally receive design reference files (COR, DGN, SEC, PERF, TST, DBT, A11Y, DOC, TRC), substitute the bugfix baseline docs:
|
||||
@@ -480,7 +480,7 @@ fallback is retired with the design pipeline, [org-internal #3072] phase 3):
|
||||
```
|
||||
5. The `{CONTRADICTION_RULE}` is weakened: code that contradicts repro-notes/impl-notes is a MAJOR — there is no design to elevate to BLOCKER.
|
||||
6. All other Phase A dispatch rules (reviewer comment posting, commit status, reviewer prompt template, temperature, permissions, worktree-path rule) apply unchanged.
|
||||
7. Efficiency optimization (round 2+, [org-internal #2598]): follows the shared Phase D rule (`_shared/review-pipeline-phases.md` Phase D "Efficiency optimization") with no standalone-mode deviation — partial re-dispatch, full sweep every 2 rounds, delta-scoped reviewer input.
|
||||
7. Efficiency optimization (round 2+, [TT-2598]): follows the shared Phase D rule (`_shared/review-pipeline-phases.md` Phase D "Efficiency optimization") with no standalone-mode deviation — partial re-dispatch, full sweep every 2 rounds, delta-scoped reviewer input.
|
||||
|
||||
**Orchestrator actions**:
|
||||
|
||||
@@ -498,7 +498,7 @@ fallback is retired with the design pipeline, [org-internal #3072] phase 3):
|
||||
|
||||
2. Initialize or update review status by posting a commit status via `POST /api/v1/repos/Octopus/octopus/statuses/{sha}` (`_shared/gitea-write-patterns.md` Pattern 8) with context `pipeline/review-code`. The commit-status payload carries `state` and `description`; the full review lifecycle state is documented in `core/schemas/review-status.schema.json` and tracked by the `octopus review status` CLI.
|
||||
|
||||
2.5. **Mechanical-green gate (mandatory, [org-internal #2598])** — before spawning ANY reviewer,
|
||||
2.5. **Mechanical-green gate (mandatory, [TT-2598])** — before spawning ANY reviewer,
|
||||
run `bun core/skills/review-code/scripts/precondition-gate.ts {slug} --round {N}`
|
||||
from the worktree root. Exit 0 → continue to step 3. Exit 1 → the script has
|
||||
appended a PRECONDITION-BLOCK record (Tier 1,
|
||||
@@ -516,7 +516,7 @@ fallback is retired with the design pipeline, [org-internal #3072] phase 3):
|
||||
|
||||
3. Spawn **all reviewers in parallel** (10 in pipeline mode at Large tier; fewer at Small/Medium tiers; DGN skipped in standalone-bugfix mode). Each reviewer receives:
|
||||
- The standardized prompt (above) with dimension-specific values filled in.
|
||||
- For round ≥ 2 ([org-internal #2598] delta scoping): `{FILE_SECTIONS}` lists ONLY the
|
||||
- For round ≥ 2 ([TT-2598] delta scoping): `{FILE_SECTIONS}` lists ONLY the
|
||||
files revised since the previous round plus their 3–5 convention-comparison
|
||||
neighbors — not the round-1 full file set. Round 1 keeps the full set.
|
||||
- Agent type: Explorer.
|
||||
@@ -607,7 +607,7 @@ fallback is retired with the design pipeline, [org-internal #3072] phase 3):
|
||||
- Updates review status by posting a commit status via `POST /api/v1/repos/Octopus/octopus/statuses/{sha}` (`_shared/gitea-write-patterns.md` Pattern 8)with context `pipeline/review-code`.
|
||||
- Persists its return summary to
|
||||
`<runs-root>/{slug}/reviews/code/round{N}/synthesis-return.md` (Tier 1,
|
||||
worker-report persistence [org-internal #2847] — see
|
||||
worker-report persistence [TT-2847] — see
|
||||
`_shared/worker-report-persistence.md`) BEFORE returning, and registers
|
||||
the `index.json` row (type `other`, schema null, stage `review-code`,
|
||||
produced_by `Synthesizer`). The persisted copy is the report of record —
|
||||
@@ -633,240 +633,14 @@ fallback is retired with the design pipeline, [org-internal #3072] phase 3):
|
||||
---
|
||||
|
||||
<!-- section:phase-c -->
|
||||
## Phase C — Developer Revision
|
||||
### Phase C+D — Developer Revision & Re-review Loop — see `reference/revision-loop.md`
|
||||
|
||||
If `overall_verdict` is PASS, skip to Phase E.
|
||||
> Phase C (Developer revision: task-file preparation, revision survival via
|
||||
> `task_id` resume, convergence tracking) and Phase D (re-review loop until
|
||||
> convergence or round budget exhaustion) live in
|
||||
> `reference/revision-loop.md`. Read it when `overall_verdict` is not PASS.
|
||||
> On PASS, skip both phases and proceed to Phase E.
|
||||
|
||||
Otherwise:
|
||||
|
||||
**Orchestrator actions**:
|
||||
|
||||
1. Prepare the Developer's input as a structured task file,
|
||||
created as a wiki page via `wiki 读写 API(见 TERMINOLOGY)` (`_shared/gitea-write-patterns.md` Pattern 1)with page_name `{slug}/reviews/code/round{N}/task-developer`.
|
||||
|
||||
This file must contain:
|
||||
- Paths to all code files that need revision.
|
||||
- Reference to the synthesis comment on the ticket (posted via `工单评论 API(见 TERMINOLOGY)` in Phase B — Tier 2).
|
||||
- References to the Tier 1 finding files for dimensions that have FAIL or WARN
|
||||
verdicts (`<runs-root>/{slug}/reviews/code/round{N}/findings-{DIMENSION_CODE}.json`).
|
||||
- The Developer MUST NOT receive the full text of all reviewer findings
|
||||
inline — use finding-file path references only to avoid context explosion.
|
||||
- Convergence status: blockers/majors remaining vs. previous round.
|
||||
- **Revision survival ([org-internal #2601]) — primary path**: the task tool's completion
|
||||
output includes a `task_id`; passing it back resumes the SAME Developer
|
||||
subagent session instead of creating a fresh one. Round 1: persist the
|
||||
returned `task_id` with the round's working-notes entry (it must survive
|
||||
round-boundary compaction). Round ≥ 2: dispatch with `task_id` set to the
|
||||
previous revision round's — the Developer continues in-session with its
|
||||
prior diff/context; the round's task page then carries only the findings
|
||||
delta, not a full re-derivation. Reviewers are NEVER resumed — per-round
|
||||
freshness is their independence.
|
||||
- **Revision survival — fallback** (task_id lost to compaction before it
|
||||
was persisted): prepend the current `<runs-root>/{slug}/working-notes.md`
|
||||
content (run narrative memory — prior decisions, dead ends, reviewer
|
||||
feedback from earlier rounds) and reference the previous round's revision
|
||||
summary (`{slug}/reviews/code/round{N-1}/revision-summary`), stating
|
||||
explicitly that this revises code a prior round already wrote — do NOT
|
||||
re-read the full design/acceptance artifacts unless a finding requires
|
||||
them.
|
||||
|
||||
2. Spawn the Developer (Worker) with the prompt
|
||||
template at `core/skills/_shared/review-revision-prompt.md`, substituting:
|
||||
|
||||
- `{ROLE}`: Developer
|
||||
- `{TASK_FILE}`: task-developer
|
||||
- `{REVISION_SCOPE}`: Apply the Developer Revision Protocol (see Protocol
|
||||
subsection below) — evaluate each finding against codebase reality:
|
||||
Explorer reviewers are automated LLM sub-agents that can hallucinate
|
||||
citations, misapply rules, or miss design context. Verify cited code
|
||||
exists, the rule applies, and the fix does not break existing
|
||||
functionality. WAIVE technically-incorrect findings with justification
|
||||
(`WAIVED-{finding-id}` → one-line reason; canonical definition of the
|
||||
`WAIVED-{id}` convention, incl. the round-2+ cosmetic-MINOR waiver
|
||||
rule: `_shared/review-revision-prompt.md`). Revise code minimally and
|
||||
surgically — do NOT refactor unrelated code or introduce new behavior.
|
||||
- `{RESOLUTION_RULE}`: Do NOT silently deviate from the approved baseline
|
||||
(DAG task mode: the node spec + frozen cross-session contracts in
|
||||
`{epic-slug}/dag`; the legacy `{slug}/03-design-*` baseline is archived
|
||||
historical, [org-internal #3072] phase 3). If a finding exposes a design flaw, mark it
|
||||
as deferred with justification and suggest a design amendment — do not
|
||||
change the code against the baseline.
|
||||
- `{COSMETIC_MINOR_EXAMPLES}`: naming, comments, dead code, import
|
||||
ordering, style
|
||||
- `{WAIVED_EXAMPLE}`: `WAIVED-COR-R2-001`
|
||||
- `{CHECKLIST_REF}`: `core/checklists/code-review.md`
|
||||
- `{FILES_MODIFIED_LINE}`: {list}
|
||||
- `{RETURN_FILE}`:
|
||||
`<runs-root>/{slug}/reviews/code/round{N}/revision-return.md`
|
||||
(Tier 1 return persistence — [org-internal #2847],
|
||||
`_shared/worker-report-persistence.md`)
|
||||
|
||||
3. The Developer revises the code files in place. The Developer creates a
|
||||
revision summary as a wiki page via `wiki 读写 API(见 TERMINOLOGY)` (`_shared/gitea-write-patterns.md` Pattern 1)with page_name `{slug}/reviews/code/round{N}/revision-summary`,
|
||||
and persists its final return summary to
|
||||
`<runs-root>/{slug}/reviews/code/round{N}/revision-return.md` (Tier 1,
|
||||
worker-report persistence [org-internal #2847] — see
|
||||
`_shared/worker-report-persistence.md`) BEFORE returning. If the
|
||||
completion notification is lost, the Orchestrator recovers the revision
|
||||
outcome from the persisted return (wiki page for the full summary,
|
||||
Tier 1 file for the conclusion of record).
|
||||
|
||||
4. **Pre-handoff gate** — before reporting completion, the Developer MUST run
|
||||
the same mechanical gate the Orchestrator will re-run at Phase D re-entry
|
||||
(the tree-fingerprint cache turns the re-run into a cache hit — one real
|
||||
execution per tree state, no double-paying):
|
||||
- Run `bun core/skills/review-code/scripts/precondition-gate.ts {slug} --round {N}`
|
||||
from the worktree root (oxlint + typecheck + `test:changed`, CI-aligned —
|
||||
`bun run test:parallel` is verify's job, not a per-revision
|
||||
requirement ([org-internal #2598])).
|
||||
- Exit 0 required; a new test failure, lint error, or type error introduced
|
||||
by the revision must be fixed before the Orchestrator proceeds to Phase D.
|
||||
- Report the gate's per-check results in the revision summary.
|
||||
|
||||
---
|
||||
|
||||
### Phase C — Developer Revision: Protocol
|
||||
|
||||
The Developer applies this cognitive protocol before implementing any finding.
|
||||
**Core principle:** reviewer findings are claims to evaluate, not orders to
|
||||
execute. Verify before implementing. Technical correctness over performative
|
||||
agreement.
|
||||
|
||||
#### Response Pattern
|
||||
|
||||
1. **READ** — Load every FAIL/WARN dimension finding file
|
||||
(`<runs-root>/{slug}/reviews/code/round{N}/findings-{DIMENSION_CODE}.json`,
|
||||
Tier 1 local). Do not react item-by-item.
|
||||
2. **UNDERSTAND** — Restate each finding's requirement in your own words.
|
||||
If you cannot, the finding is unclear — see STOP rule below.
|
||||
3. **VERIFY** — Check the finding against codebase reality: does the cited
|
||||
code exist at the given file:line? Does the cited rule apply?
|
||||
4. **EVALUATE** — Is the finding technically correct for THIS codebase?
|
||||
Does the proposed fix break existing functionality? Does it conflict
|
||||
with the approved baseline (DAG task mode: the node spec + contracts in
|
||||
`{epic-slug}/dag`)?
|
||||
5. **RESPOND** — Fix it (correct), WAIVE it (`WAIVED-{finding-id}` →
|
||||
one-line reason), or flag it (unclear / design-level question).
|
||||
6. **IMPLEMENT** — One verified finding at a time, test each individually.
|
||||
|
||||
#### Evaluating Findings — 5-Check Gate
|
||||
|
||||
Before implementing any finding, run these checks:
|
||||
|
||||
1. **Cited code is real** — Open the file:line. Does the code exist and say
|
||||
what the finding claims?
|
||||
2. **Rule applies** — Does the cited checklist rule actually match this issue?
|
||||
3. **Reason for current implementation** — Is the flagged behavior
|
||||
intentional? Check the baseline (node spec + contracts in
|
||||
`{epic-slug}/dag` for DAG task mode) for rationale.
|
||||
4. **Fix does not break existing functionality** — Will the proposed change
|
||||
cause a regression?
|
||||
5. **Reviewer has full context** — Did the reviewer see the baseline (node
|
||||
spec + acceptance criteria) and the diff context? An isolated diff review
|
||||
can miss architectural intent.
|
||||
|
||||
```
|
||||
IF a finding seems wrong:
|
||||
WAIVE it: WAIVED-{finding-id} → <one-line technical reason>
|
||||
|
||||
IF you cannot easily verify a finding:
|
||||
State the limitation in revision_summary.md and request direction.
|
||||
|
||||
IF a finding conflicts with the approved design:
|
||||
Flag as a design-level question — do NOT silently change code against the design.
|
||||
```
|
||||
|
||||
#### Unclear Findings — STOP Rule
|
||||
|
||||
```
|
||||
IF any finding is unclear:
|
||||
STOP — do not implement ANY finding yet.
|
||||
Flag the unclear items in revision_summary.md and request clarification.
|
||||
|
||||
WHY: findings may be related. Partial understanding produces wrong
|
||||
implementation across multiple items.
|
||||
```
|
||||
|
||||
**Example:** The synthesis lists findings F1–F6. You understand F1, F2, F3, F6.
|
||||
F4 and F5 are ambiguous about what change is expected.
|
||||
- **WRONG:** implement F1, F2, F3, F6 now; ask about F4, F5 later.
|
||||
- **RIGHT:** "Understand F1, F2, F3, F6. Need clarification on F4, F5 before
|
||||
proceeding — they may interact with the same module."
|
||||
|
||||
#### YAGNI Check
|
||||
|
||||
```
|
||||
IF a reviewer suggests "implementing this properly" (full abstraction,
|
||||
generic API, configurable layer):
|
||||
Check actual usage (codegraph callers / grep) BEFORE expanding scope.
|
||||
|
||||
IF unused: WAIVE — "No call sites found. Leaving as-is (YAGNI)."
|
||||
IF used: Then implement properly.
|
||||
```
|
||||
|
||||
#### Forbidden Responses in revision_summary.md
|
||||
|
||||
**NEVER** write:
|
||||
- "You're absolutely right!" / "Great point!" / "Excellent catch!" — performative.
|
||||
- "Thanks for catching that!" / any gratitude expression.
|
||||
- "Let me implement that now" — before verification.
|
||||
|
||||
**INSTEAD:**
|
||||
- Restate the technical requirement concisely.
|
||||
- State the fix factually: `Fixed {finding-id}: <what changed> at <file:line>`.
|
||||
- Just fix it and show the result in the diff.
|
||||
|
||||
#### Gracefully Correcting a WAIVE
|
||||
|
||||
If you WAIVEd a finding and were wrong:
|
||||
```
|
||||
"Verified {finding-id} — the reviewer is correct. My initial read missed
|
||||
<reason>. Implementing now."
|
||||
```
|
||||
State the correction factually. No lengthy apology.
|
||||
|
||||
#### Implementation Order
|
||||
|
||||
For multi-finding revisions, after clarifying all unclear items:
|
||||
1. **Blocking issues** — security, data loss, breaks existing functionality.
|
||||
2. **Simple fixes** — typos, imports, naming, dead code.
|
||||
3. **Complex fixes** — logic changes, refactoring within minimal-surgical scope.
|
||||
Test each fix individually.
|
||||
|
||||
#### Rationalization-Anticipation Quick Reference
|
||||
|
||||
| Trap | Hold to |
|
||||
|------|---------|
|
||||
| "The reviewer flagged it as BLOCKER, so it must be real." | VERIFY cited code exists and rule applies before any edit. |
|
||||
| "Just fix everything to avoid a re-review round." | EVALUATE each finding; WAIVE the wrong ones with reasoning. |
|
||||
| "This finding looks plausible — I'll fix it without checking." | Open the file:line, confirm the behavior. |
|
||||
| "I'll implement the clear findings and ask about unclear ones later." | STOP. Clarify ALL unclear items before implementing any. |
|
||||
| "The reviewer wants it done 'properly' — full abstraction." | Check call sites first. If unused, WAIVE (YAGNI). |
|
||||
| "I shouldn't push back — the reviewer is probably right." | Push back with technical reasoning. The diff is the acknowledgment. |
|
||||
|
||||
---
|
||||
|
||||
<!-- section:phase-d -->
|
||||
## Phase D — Re-review Loop
|
||||
|
||||
After the Developer completes revision:
|
||||
|
||||
1. Increment the round counter (the Synthesizer updates the commit status in Phase B
|
||||
with the new round's results).
|
||||
2. Re-enter Phase A at step 2.5 — the mechanical-green gate re-runs on the
|
||||
revised tree before any reviewer spawn (a red gate blocks dispatch exactly
|
||||
as on round-1 entry) — then spawn the new round of reviewers against the
|
||||
revised files.
|
||||
|
||||
**Convergence criteria**: see `core/skills/_shared/review-pipeline-phases.md` Phase D for the canonical table (stop conditions). `{MAX_ROUNDS}` is per-skill — code review binds the routing budget: **2** rounds default, **3** for high risk (a BLOCKER survived a round, or the diff touches a frozen cross-session contract) — `<instance-root>/workflow-routing.yaml` `review.max_rounds` ([org-internal #3567]). The code-review-specific addition is inheritance of the shared INFO-disposition rule. The shared Round-3 Escalation Guardrail is scoped to the `review-artifact` skill targets only and does not apply here.
|
||||
|
||||
**Round budget (mandatory, [org-internal #3567])**: when `current_round` reaches the budget (2; 3 for high risk) without convergence, do NOT enter another round. STOP: register every remaining BLOCKER/MAJOR finding as TD registry rows (`rules/ticket-lifecycle.md`), record the verdict (FAIL if any BLOCKER remains, else PASS — the debt is carried by the TD registry rows just registered), and close the loop. A review that cannot converge within budget is a design-level stall wearing review clothes (retro 2026-08-21 / [org-internal #3050]): in DAG task mode, map it to the DAG oversize signals (`<instance-root>/workflow-routing.yaml` `dag.size_derivation.oversize_signals`) and let the aggregator agent drive re-derivation + a `review-dag` re-run; otherwise record the design-level finding on the Epic, or open `{slug}/03-design-amendments` via `wiki 读写 API(见 TERMINOLOGY)` (`_shared/gitea-write-patterns.md` Pattern 1).
|
||||
|
||||
**Efficiency optimization**: see `core/skills/_shared/review-pipeline-phases.md` Phase D (same rule — from round 2 onward ([org-internal #2598]), only spawn reviewers for FAIL/WARN/UNRESOLVED dimensions; full sweep every 2 rounds). Round ≥2 reviewer input is delta-scoped to the revised files + their neighbors.
|
||||
|
||||
<!-- inject: ../_shared/compaction-round-boundary.md -->
|
||||
|
||||
---
|
||||
|
||||
<!-- section:phase-e -->
|
||||
## Phase E — Final Report & Approval
|
||||
@@ -912,11 +686,11 @@ After the Developer completes revision:
|
||||
the findings JSONs are deleted at Tier 1 archive-at-close, so the final
|
||||
report is the ONLY durable carrier of round-1 findings — retrospective
|
||||
M7 (§2.9 first-round root-cause analysis) reads this table instead of
|
||||
relying on commit messages (retro 2026-08-21 / [org-internal #3120]).
|
||||
relying on commit messages (retro 2026-08-21 / [TT-3120]).
|
||||
|
||||
2.56. **Inline-ization — post the final round's findings as PR inline
|
||||
comments** (consumer of frozen contract
|
||||
`{epic-slug}/shared/review-inline-v1`, epic [org-internal #3533]; REQ-F-001/002/004).
|
||||
`{epic-slug}/shared/review-inline-v1`, epic [TT-3533]; REQ-F-001/002/004).
|
||||
After the final report page exists (step 1), post the FINAL round's
|
||||
findings as Gitea PR inline comments so review conclusions land
|
||||
line-level on the diff. Run the runner from the repo root:
|
||||
@@ -974,12 +748,13 @@ After the Developer completes revision:
|
||||
`question` tool, passing `stage: "review-code"`:
|
||||
|
||||
> **Gitea approval timing (mandatory when the PR needs a human approval
|
||||
> gate)**: register the reviewer FIRST via `gitea_pull__add_reviewer`,
|
||||
> gate)**: register the reviewer FIRST via
|
||||
> `POST <gitea-base-url>/api/v1/repos/{owner}/{repo}/pulls/{index}/requested_reviewers`,
|
||||
> wait for the `REQUEST_REVIEW` registration to be recorded, and only
|
||||
> THEN ask the human to approve. Approving before the reviewer is
|
||||
> registered produces `official: false` on the approval — the gate
|
||||
> treats the PR as unapproved and the approval must be re-done. See
|
||||
> `_shared/review-pipeline-phases.md` Phase E step 3.5. ([org-internal #1931]: audit
|
||||
> `_shared/review-pipeline-phases.md` Phase E step 3.5. ([TT-1931]: audit
|
||||
> R2→R3 re-loop + re-approve, ~30min wasted on exactly this ordering.)
|
||||
|
||||
```
|
||||
@@ -987,7 +762,7 @@ After the Developer completes revision:
|
||||
Final verdict: {PASS | WARN | FAIL}
|
||||
Converged: {true | false}
|
||||
|
||||
See full report: wiki page `{slug}/reviews/code/final/report` (DAG task mode: `{epic-slug}/reviews/code/final/report-task-{node-id}`)(via `gitea_wiki__get_page`,`_shared/gitea-read-patterns.md` Pattern 1)
|
||||
See full report: wiki page `{slug}/reviews/code/final/report` (DAG task mode: `{epic-slug}/reviews/code/final/report-task-{node-id}`)(via `GET <gitea-base-url>/api/v1/repos/{owner}/{repo}/wiki/page/{mangled-name}` — `sub_url` resolved from `GET .../wiki/pages` first, `_shared/gitea-read-patterns.md` Pattern 1)
|
||||
All review artifacts: ticket #{issue_number} comments + wiki pages under `{slug}/reviews/code/`(DAG task mode: under `{epic-slug}/reviews/code/`, Tier 1 round artifacts under `<runs-root>/{epic-slug}-task-{node-id}/reviews/code/`)
|
||||
Inline comments(only when step 2.56 ran;omit for no-PR flows): `inline: X posted / Y file-level / Z fallback / W failed`
|
||||
|
||||
@@ -1057,7 +832,7 @@ To notify workflow completion, call the `signal_stage_done` tool.
|
||||
- Legacy design path (historical note, FLOW-F001 / audit-20260901): the
|
||||
design-document precondition row formerly in the DAG task-mode table
|
||||
(legacy `{slug}/03-design-index` / `{slug}/02-03-req-design` → node spec + frozen DAG
|
||||
copy) referenced the legacy design pipeline, archived 2026-08-21 with [org-internal #3072]
|
||||
copy) referenced the legacy design pipeline, archived 2026-08-21 with [TT-3072]
|
||||
phase 3 (see `<instance-root>/archive/skills/design/`); the live design baseline is
|
||||
the node spec + cross-session edge contracts in the frozen DAG copy
|
||||
`{epic-slug}/dag`.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Code Review Output Artifacts
|
||||
|
||||
> Output tree for code review artifacts. Read on-demand for reference.
|
||||
> Output model ([org-internal #1988] Tier 1 migration): Tier 1 local files (raw dimension findings) + Tier 2 wiki pages (task prompts, revision summaries, final reports) + Tier 2 synthesis comment. Status tracking via commit status `pipeline/review-code`.
|
||||
> Output model ([TT-1988] Tier 1 migration): Tier 1 local files (raw dimension findings) + Tier 2 wiki pages (task prompts, revision summaries, final reports) + Tier 2 synthesis comment. Status tracking via commit status `pipeline/review-code`.
|
||||
|
||||
```
|
||||
<runs-root>/{slug}/reviews/code/
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
> Extracted from review-code/SKILL.md (Phase C — Developer Revision +
|
||||
> Phase D — Re-review Loop) — moved verbatim; read on-demand when
|
||||
> `overall_verdict` is not PASS (skipped entirely on PASS, which jumps
|
||||
> straight to Phase E).
|
||||
|
||||
<!-- section:phase-c -->
|
||||
## Phase C — Developer Revision
|
||||
|
||||
If `overall_verdict` is PASS, skip to Phase E.
|
||||
|
||||
Otherwise:
|
||||
|
||||
**Orchestrator actions**:
|
||||
|
||||
1. Prepare the Developer's input as a structured task file,
|
||||
created as a wiki page via `wiki 读写 API(见 TERMINOLOGY)` (`_shared/gitea-write-patterns.md` Pattern 1)with page_name `{slug}/reviews/code/round{N}/task-developer`.
|
||||
|
||||
This file must contain:
|
||||
- Paths to all code files that need revision.
|
||||
- Reference to the synthesis comment on the ticket (posted via `工单评论 API(见 TERMINOLOGY)` in Phase B — Tier 2).
|
||||
- References to the Tier 1 finding files for dimensions that have FAIL or WARN
|
||||
verdicts (`<runs-root>/{slug}/reviews/code/round{N}/findings-{DIMENSION_CODE}.json`).
|
||||
- The Developer MUST NOT receive the full text of all reviewer findings
|
||||
inline — use finding-file path references only to avoid context explosion.
|
||||
- Convergence status: blockers/majors remaining vs. previous round.
|
||||
- **Revision survival ([TT-2601]) — primary path**: the task tool's completion
|
||||
output includes a `task_id`; passing it back resumes the SAME Developer
|
||||
subagent session instead of creating a fresh one. Round 1: persist the
|
||||
returned `task_id` with the round's working-notes entry (it must survive
|
||||
round-boundary compaction). Round ≥ 2: dispatch with `task_id` set to the
|
||||
previous revision round's — the Developer continues in-session with its
|
||||
prior diff/context; the round's task page then carries only the findings
|
||||
delta, not a full re-derivation. Reviewers are NEVER resumed — per-round
|
||||
freshness is their independence.
|
||||
- **Revision survival — fallback** (task_id lost to compaction before it
|
||||
was persisted): prepend the current `<runs-root>/{slug}/working-notes.md`
|
||||
content (run narrative memory — prior decisions, dead ends, reviewer
|
||||
feedback from earlier rounds) and reference the previous round's revision
|
||||
summary (`{slug}/reviews/code/round{N-1}/revision-summary`), stating
|
||||
explicitly that this revises code a prior round already wrote — do NOT
|
||||
re-read the full design/acceptance artifacts unless a finding requires
|
||||
them.
|
||||
|
||||
2. Spawn the Developer (Worker) with the prompt
|
||||
template at `core/skills/_shared/review-revision-prompt.md`, substituting:
|
||||
|
||||
- `{ROLE}`: Developer
|
||||
- `{TASK_FILE}`: task-developer
|
||||
- `{REVISION_SCOPE}`: Apply the Developer Revision Protocol (see Protocol
|
||||
subsection below) — evaluate each finding against codebase reality:
|
||||
Explorer reviewers are automated LLM sub-agents that can hallucinate
|
||||
citations, misapply rules, or miss design context. Verify cited code
|
||||
exists, the rule applies, and the fix does not break existing
|
||||
functionality. WAIVE technically-incorrect findings with justification
|
||||
(`WAIVED-{finding-id}` → one-line reason; canonical definition of the
|
||||
`WAIVED-{id}` convention, incl. the round-2+ cosmetic-MINOR waiver
|
||||
rule: `_shared/review-revision-prompt.md`). Revise code minimally and
|
||||
surgically — do NOT refactor unrelated code or introduce new behavior.
|
||||
- `{RESOLUTION_RULE}`: Do NOT silently deviate from the approved baseline
|
||||
(DAG task mode: the node spec + frozen cross-session contracts in
|
||||
`{epic-slug}/dag`; the legacy `{slug}/03-design-*` baseline is archived
|
||||
historical, [TT-3072] phase 3). If a finding exposes a design flaw, mark it
|
||||
as deferred with justification and suggest a design amendment — do not
|
||||
change the code against the baseline.
|
||||
- `{COSMETIC_MINOR_EXAMPLES}`: naming, comments, dead code, import
|
||||
ordering, style
|
||||
- `{WAIVED_EXAMPLE}`: `WAIVED-COR-R2-001`
|
||||
- `{CHECKLIST_REF}`: `core/checklists/code-review.md`
|
||||
- `{FILES_MODIFIED_LINE}`: {list}
|
||||
- `{RETURN_FILE}`:
|
||||
`<runs-root>/{slug}/reviews/code/round{N}/revision-return.md`
|
||||
(Tier 1 return persistence — [TT-2847],
|
||||
`_shared/worker-report-persistence.md`)
|
||||
|
||||
3. The Developer revises the code files in place. The Developer creates a
|
||||
revision summary as a wiki page via `wiki 读写 API(见 TERMINOLOGY)` (`_shared/gitea-write-patterns.md` Pattern 1)with page_name `{slug}/reviews/code/round{N}/revision-summary`,
|
||||
and persists its final return summary to
|
||||
`<runs-root>/{slug}/reviews/code/round{N}/revision-return.md` (Tier 1,
|
||||
worker-report persistence [TT-2847] — see
|
||||
`_shared/worker-report-persistence.md`) BEFORE returning. If the
|
||||
completion notification is lost, the Orchestrator recovers the revision
|
||||
outcome from the persisted return (wiki page for the full summary,
|
||||
Tier 1 file for the conclusion of record).
|
||||
|
||||
4. **Pre-handoff gate** — before reporting completion, the Developer MUST run
|
||||
the same mechanical gate the Orchestrator will re-run at Phase D re-entry
|
||||
(the tree-fingerprint cache turns the re-run into a cache hit — one real
|
||||
execution per tree state, no double-paying):
|
||||
- Run `bun core/skills/review-code/scripts/precondition-gate.ts {slug} --round {N}`
|
||||
from the worktree root (oxlint + typecheck + `test:changed`, CI-aligned —
|
||||
`bun run test:parallel` is verify's job, not a per-revision
|
||||
requirement ([TT-2598])).
|
||||
- Exit 0 required; a new test failure, lint error, or type error introduced
|
||||
by the revision must be fixed before the Orchestrator proceeds to Phase D.
|
||||
- Report the gate's per-check results in the revision summary.
|
||||
|
||||
---
|
||||
|
||||
### Phase C — Developer Revision: Protocol
|
||||
|
||||
The Developer applies this cognitive protocol before implementing any finding.
|
||||
**Core principle:** reviewer findings are claims to evaluate, not orders to
|
||||
execute. Verify before implementing. Technical correctness over performative
|
||||
agreement.
|
||||
|
||||
#### Response Pattern
|
||||
|
||||
1. **READ** — Load every FAIL/WARN dimension finding file
|
||||
(`<runs-root>/{slug}/reviews/code/round{N}/findings-{DIMENSION_CODE}.json`,
|
||||
Tier 1 local). Do not react item-by-item.
|
||||
2. **UNDERSTAND** — Restate each finding's requirement in your own words.
|
||||
If you cannot, the finding is unclear — see STOP rule below.
|
||||
3. **VERIFY** — Check the finding against codebase reality: does the cited
|
||||
code exist at the given file:line? Does the cited rule apply?
|
||||
4. **EVALUATE** — Is the finding technically correct for THIS codebase?
|
||||
Does the proposed fix break existing functionality? Does it conflict
|
||||
with the approved baseline (DAG task mode: the node spec + contracts in
|
||||
`{epic-slug}/dag`)?
|
||||
5. **RESPOND** — Fix it (correct), WAIVE it (`WAIVED-{finding-id}` →
|
||||
one-line reason), or flag it (unclear / design-level question).
|
||||
6. **IMPLEMENT** — One verified finding at a time, test each individually.
|
||||
|
||||
#### Evaluating Findings — 5-Check Gate
|
||||
|
||||
Before implementing any finding, run these checks:
|
||||
|
||||
1. **Cited code is real** — Open the file:line. Does the code exist and say
|
||||
what the finding claims?
|
||||
2. **Rule applies** — Does the cited checklist rule actually match this issue?
|
||||
3. **Reason for current implementation** — Is the flagged behavior
|
||||
intentional? Check the baseline (node spec + contracts in
|
||||
`{epic-slug}/dag` for DAG task mode) for rationale.
|
||||
4. **Fix does not break existing functionality** — Will the proposed change
|
||||
cause a regression?
|
||||
5. **Reviewer has full context** — Did the reviewer see the baseline (node
|
||||
spec + acceptance criteria) and the diff context? An isolated diff review
|
||||
can miss architectural intent.
|
||||
|
||||
```
|
||||
IF a finding seems wrong:
|
||||
WAIVE it: WAIVED-{finding-id} → <one-line technical reason>
|
||||
|
||||
IF you cannot easily verify a finding:
|
||||
State the limitation in revision_summary.md and request direction.
|
||||
|
||||
IF a finding conflicts with the approved design:
|
||||
Flag as a design-level question — do NOT silently change code against the design.
|
||||
```
|
||||
|
||||
#### Unclear Findings — STOP Rule
|
||||
|
||||
```
|
||||
IF any finding is unclear:
|
||||
STOP — do not implement ANY finding yet.
|
||||
Flag the unclear items in revision_summary.md and request clarification.
|
||||
|
||||
WHY: findings may be related. Partial understanding produces wrong
|
||||
implementation across multiple items.
|
||||
```
|
||||
|
||||
**Example:** The synthesis lists findings F1–F6. You understand F1, F2, F3, F6.
|
||||
F4 and F5 are ambiguous about what change is expected.
|
||||
- **WRONG:** implement F1, F2, F3, F6 now; ask about F4, F5 later.
|
||||
- **RIGHT:** "Understand F1, F2, F3, F6. Need clarification on F4, F5 before
|
||||
proceeding — they may interact with the same module."
|
||||
|
||||
#### YAGNI Check
|
||||
|
||||
```
|
||||
IF a reviewer suggests "implementing this properly" (full abstraction,
|
||||
generic API, configurable layer):
|
||||
Check actual usage (codegraph callers / grep) BEFORE expanding scope.
|
||||
|
||||
IF unused: WAIVE — "No call sites found. Leaving as-is (YAGNI)."
|
||||
IF used: Then implement properly.
|
||||
```
|
||||
|
||||
#### Forbidden Responses in revision_summary.md
|
||||
|
||||
**NEVER** write:
|
||||
- "You're absolutely right!" / "Great point!" / "Excellent catch!" — performative.
|
||||
- "Thanks for catching that!" / any gratitude expression.
|
||||
- "Let me implement that now" — before verification.
|
||||
|
||||
**INSTEAD:**
|
||||
- Restate the technical requirement concisely.
|
||||
- State the fix factually: `Fixed {finding-id}: <what changed> at <file:line>`.
|
||||
- Just fix it and show the result in the diff.
|
||||
|
||||
#### Gracefully Correcting a WAIVE
|
||||
|
||||
If you WAIVEd a finding and were wrong:
|
||||
```
|
||||
"Verified {finding-id} — the reviewer is correct. My initial read missed
|
||||
<reason>. Implementing now."
|
||||
```
|
||||
State the correction factually. No lengthy apology.
|
||||
|
||||
#### Implementation Order
|
||||
|
||||
For multi-finding revisions, after clarifying all unclear items:
|
||||
1. **Blocking issues** — security, data loss, breaks existing functionality.
|
||||
2. **Simple fixes** — typos, imports, naming, dead code.
|
||||
3. **Complex fixes** — logic changes, refactoring within minimal-surgical scope.
|
||||
Test each fix individually.
|
||||
|
||||
#### Rationalization-Anticipation Quick Reference
|
||||
|
||||
| Trap | Hold to |
|
||||
|------|---------|
|
||||
| "The reviewer flagged it as BLOCKER, so it must be real." | VERIFY cited code exists and rule applies before any edit. |
|
||||
| "Just fix everything to avoid a re-review round." | EVALUATE each finding; WAIVE the wrong ones with reasoning. |
|
||||
| "This finding looks plausible — I'll fix it without checking." | Open the file:line, confirm the behavior. |
|
||||
| "I'll implement the clear findings and ask about unclear ones later." | STOP. Clarify ALL unclear items before implementing any. |
|
||||
| "The reviewer wants it done 'properly' — full abstraction." | Check call sites first. If unused, WAIVE (YAGNI). |
|
||||
| "I shouldn't push back — the reviewer is probably right." | Push back with technical reasoning. The diff is the acknowledgment. |
|
||||
|
||||
---
|
||||
|
||||
<!-- section:phase-d -->
|
||||
## Phase D — Re-review Loop
|
||||
|
||||
After the Developer completes revision:
|
||||
|
||||
1. Increment the round counter (the Synthesizer updates the commit status in Phase B
|
||||
with the new round's results).
|
||||
2. Re-enter Phase A at step 2.5 — the mechanical-green gate re-runs on the
|
||||
revised tree before any reviewer spawn (a red gate blocks dispatch exactly
|
||||
as on round-1 entry) — then spawn the new round of reviewers against the
|
||||
revised files.
|
||||
|
||||
**Convergence criteria**: see `core/skills/_shared/review-pipeline-phases.md` Phase D for the canonical table (stop conditions). `{MAX_ROUNDS}` is per-skill — code review binds the routing budget: **2** rounds default, **3** for high risk (a BLOCKER survived a round, or the diff touches a frozen cross-session contract) — `<instance-root>/workflow-routing.yaml` `review.max_rounds` ([TT-3567]). The code-review-specific addition is inheritance of the shared INFO-disposition rule. The shared Round-3 Escalation Guardrail is scoped to the `review-artifact` skill targets only and does not apply here.
|
||||
|
||||
**Round budget (mandatory, [TT-3567])**: when `current_round` reaches the budget (2; 3 for high risk) without convergence, do NOT enter another round. STOP: register every remaining BLOCKER/MAJOR finding as TD registry rows (`rules/ticket-lifecycle.md`), record the verdict with the shared three-tier ladder (`core/schemas/synthesis.schema.json` `overall_verdict` + `core/skills/_shared/review-orchestrator-rules.md` rule 3): FAIL if any BLOCKER or FAIL dimension remains, else WARN, PASS only if every remaining dimension is PASS ([TT-4786]: the prior binary "else PASS" wording silently upgraded WARN-eligible outcomes to PASS), and close the loop. The debt is carried by the TD registry rows just registered, not by the recorded verdict. A review that cannot converge within budget is a design-level stall wearing review clothes (retro 2026-08-21 / [TT-3050]): in DAG task mode, map it to the DAG oversize signals (`<instance-root>/workflow-routing.yaml` `dag.size_derivation.oversize_signals`) and let the aggregator agent drive re-derivation + a `review-dag` re-run; otherwise record the design-level finding on the Epic, or open `{slug}/03-design-amendments` via `wiki 读写 API(见 TERMINOLOGY)` (`_shared/gitea-write-patterns.md` Pattern 1).
|
||||
|
||||
**Efficiency optimization**: see `core/skills/_shared/review-pipeline-phases.md` Phase D (same rule — from round 2 onward ([TT-2598]), only spawn reviewers for FAIL/WARN/UNRESOLVED dimensions; full sweep every 2 rounds). Round ≥2 reviewer input is delta-scoped to the revised files + their neighbors.
|
||||
|
||||
<!-- inject: ../_shared/compaction-round-boundary.md -->
|
||||
|
||||
---
|
||||
+26
-676
@@ -60,10 +60,10 @@ digraph verify {
|
||||
|
||||
## Agent Role
|
||||
|
||||
> **Progressive disclosure ([org-internal #3722], [org-internal #3734], [org-internal #3745])**: when dispatching a Verifier
|
||||
> **Progressive disclosure ([TT-3722], [TT-3734], [TT-3745])**: when dispatching a Verifier
|
||||
> scoped to one phase, pass `skills: ["verify:phase-2"]` (preamble + that
|
||||
> phase only) instead of the full body; multi-phase dispatches may union.
|
||||
> Phase 5 is subdivided ([org-internal #3734]): `phase-5` covers the report template only;
|
||||
> Phase 5 is subdivided ([TT-3734]): `phase-5` covers the report template only;
|
||||
> each mandatory filing subsection carries its own marker (`phase-5.5` tech
|
||||
> debt, `phase-5.55` baseline failures, `phase-5.56` flaky tests,
|
||||
> `phase-5.6` checklist sync, `phase-5.7` CI sync). Dispatch recipes:
|
||||
@@ -71,7 +71,7 @@ digraph verify {
|
||||
> / `phase-5.56` when baseline failures / flaky tests are present); PASS
|
||||
> close-out →
|
||||
> `"verify:phase-5,phase-5.5,phase-5.55,phase-5.56,phase-5.6,phase-5.7,phase-6"`.
|
||||
> The DAG branch is separately marked ([org-internal #3745]): `phase-6` narrows to
|
||||
> The DAG branch is separately marked ([TT-3745]): `phase-6` narrows to
|
||||
> Approval + Commit Gate, and the tail References rides `dag-branch` (same
|
||||
> tail rule as review-code's phase-e). Non-DAG dispatches thereby drop the
|
||||
> ~175-line DAG branch; DAG milestone/task verify → union `dag-branch` onto
|
||||
@@ -155,7 +155,7 @@ Before starting verification, confirm:
|
||||
node spec, its `acceptance_criteria` + `test_id` declarations, and the
|
||||
DoD slice. (Legacy tier rule — `{slug}/04-plan-*` wiki pages / issue
|
||||
comment, and the design-space + iteration-plan convergence checks that
|
||||
used to follow here — was archived 2026-08-21, [org-internal #3072] phase 3; historical
|
||||
used to follow here — was archived 2026-08-21, [TT-3072] phase 3; historical
|
||||
plan/AC pages stay readable via `_shared/gitea-read-patterns.md`.)
|
||||
- [ ] `core/checklists/verification.md` is accessible.
|
||||
- [ ] `slug` matches the run's slug (DAG: `{epic-slug}`).
|
||||
@@ -223,7 +223,7 @@ the DAG branch below for its read map):
|
||||
(The legacy `Size/*`-tiered locations — `{slug}/04-plan-*`,
|
||||
`{slug}/02-requirements-index`, `{slug}/02-03-req-design`,
|
||||
`{slug}/03-design-06-non-functional-design` — were archived 2026-08-21,
|
||||
[org-internal #3072] phase 3; historical pages stay readable for legacy-run verification
|
||||
[TT-3072] phase 3; historical pages stay readable for legacy-run verification
|
||||
via `_shared/gitea-read-patterns.md`.)
|
||||
|
||||
5. **Code review final report** — `{slug}/reviews/code/final/report`
|
||||
@@ -277,7 +277,7 @@ before. This section saves redundant typecheck/lint/security re-runs; it
|
||||
never weakens a gate.
|
||||
|
||||
**Second evidence source — the review-code precondition-gate cache
|
||||
(eff-gate-cache [org-internal #2598] / [org-internal #2990])**. The mechanical checks this phase would re-run
|
||||
(eff-gate-cache [TT-2598] / [TT-2990])**. The mechanical checks this phase would re-run
|
||||
(oxlint / typecheck / `test:changed`) are exactly the precondition-gate's
|
||||
check-set, and the gate caches GREEN results keyed on a tree fingerprint
|
||||
(HEAD + tracked diff + untracked contents) in
|
||||
@@ -394,8 +394,8 @@ For each DoD entry with verification method "Security scan":
|
||||
every failing test, run it on the last known-green commit (or the base
|
||||
branch) in isolation. **Never use `git stash` for this** — the stash stack
|
||||
is shared across all worktrees of this repo and a parallel session can
|
||||
overwrite your entry mid-flight (issue [org-internal #1655]). Instead, use the
|
||||
lifecycle-managed scratch-worktree script ([org-internal #2790]) — it registers the
|
||||
overwrite your entry mid-flight (issue [TT-1655]). Instead, use the
|
||||
lifecycle-managed scratch-worktree script ([TT-2790]) — it registers the
|
||||
worktree for the sweep backstop, symlinks `node_modules` from the source
|
||||
checkout when `bun.lock` matches (dropping the per-instance cost from
|
||||
~170k inodes to ~7k), and deregisters on removal:
|
||||
@@ -435,7 +435,7 @@ For each DoD entry with verification method "Security scan":
|
||||
### 2.7 — Browser Evidence Reference Validation (UI-touching PR)
|
||||
|
||||
For DoD entries of the「UI 主张 ↔ 可复现浏览器证据」type — contract
|
||||
`browser-evidence-4486/shared/evidence-ref-v1` (frozen 2026-09-10, [org-internal #4498]).
|
||||
`browser-evidence-4486/shared/evidence-ref-v1` (frozen 2026-09-10, [TT-4498]).
|
||||
Applicable ONLY to UI-touching PRs (changes under `packages/app`,
|
||||
`packages/ui`, or `packages/console/*` frontend surfaces):
|
||||
|
||||
@@ -493,7 +493,7 @@ Browser-evidence rows (UI-touching PRs only, Phase 2.7): ✅ PASS requires a
|
||||
mechanically validated, replayable pack-ref; `unregistered` / `manifest-missing` /
|
||||
`manifest-corrupt` / `not-replayable` / `over-limit` references are
|
||||
⚠️ UNVERIFIABLE at best — the reference channel fails explicitly, never
|
||||
silently green ([org-internal #4498] AC-4).
|
||||
silently green ([TT-4498] AC-4).
|
||||
|
||||
### Iteration Verdict
|
||||
|
||||
@@ -619,503 +619,20 @@ issue close) is performed later in Phase 5.6 — see
|
||||
`rules/issue-checklist-sync.md` § 归档动作.
|
||||
|
||||
<!-- section:phase-5.5 -->
|
||||
### Phase 5.5 — Tech Debt Registry Filing (mandatory before PASS)
|
||||
|
||||
Tech debt is filed **registry-first** (`core/rules/ticket-lifecycle.md`,
|
||||
[org-internal #3002] G1): new items become ROWS in the source ticket's `## TD 登记` comment;
|
||||
an independent ticket is created only at **promotion** (claim/schedule). There
|
||||
is no `tech-debt.md` file and no `{slug}/tech-debt` wiki page — both remain
|
||||
retired. The registry preserves the three guarantees of the old
|
||||
one-issue-per-item model: visible (the comment lives on a tracker ticket),
|
||||
individually closeable (row-level checkbox), de-duplicated across sessions
|
||||
(the TD index is stronger than title-keyword matching).
|
||||
|
||||
**Sprint-mode override ([org-internal #3002] G5/[org-internal #3007])**: read `filing.sprint-mode` from
|
||||
`<instance-root>/workflow-routing.yaml` at the START of this phase (no caching). When
|
||||
`true`, ALL severities file registry-only — registration rows are written as
|
||||
normal (severity included, nothing lost) but promotion to standalone tickets
|
||||
is FROZEN until the switch returns to `false`. Rationale: the 2026-08-12
|
||||
sprint zeroed fix capacity while filing kept running (the 125-fragment
|
||||
backlog's direct trigger); an explicit debt-side downshift beats hoping for
|
||||
discipline. BF/FT phases 5.55/5.56 are NOT covered by this switch — failure
|
||||
evidence must stay immediately visible. Flipping the switch is a human
|
||||
decision recorded on the sprint tracker; semantics in
|
||||
`rules/workflow-routing.md` §立案降档.
|
||||
|
||||
**Adjacency quota ([org-internal #3002] G3/[org-internal #3005])**: while collecting inputs, also check the
|
||||
AREAS this iteration touched (packages/modules with commits this iteration).
|
||||
If the source tickets for those areas carry applicable `## TD 登记` rows, at
|
||||
least ONE row must be taken along and disposed this iteration (fixed, or
|
||||
explicitly re-deferred with a reason — silence is not a disposition). Record
|
||||
`consumed X / applicable Y` (or `0 applicable`) in the TD report section;
|
||||
verification checklist §8.4 cross-checks it against the run's debt-quota
|
||||
record (historically the roadmap's per-chunk debt-quota line). This gives debt digestion a steady capacity source tied to
|
||||
touch, not to cleanup campaigns.
|
||||
|
||||
**Promotion quota + pull event ([org-internal #3061])**: promotion to a standalone ticket
|
||||
requires (a) a **pull event** — the row's Reactivation Trigger fired (state
|
||||
the observed event) OR a named claimer/schedule; "it seemed important" is not
|
||||
a pull event — recorded in the promotion body's `## 拉动事件 / Pull Event`
|
||||
section; and (b) the origin module's OPEN promoted-TD count is below the
|
||||
quota (**default 10** — counted **per origin module**: resolve the row's
|
||||
module from the ticket body's `Origin` field, then count that module's OPEN
|
||||
`tech-debt` tickets; retro §2.10 reports breaches). At or above quota →
|
||||
register-only until the count drops; before each Phase 5.5 promotion
|
||||
re-check the owning module's count, and a row whose module is at or above
|
||||
quota is NOT promoted — defer it and annotate the registry row with
|
||||
`quota-held` (re-checked on the next verify run, retro 2026-08-21). A row
|
||||
marked `[COLD]` by retrospective §2.10
|
||||
(unclaimed >3 retro cycles) promotes only after the pull event clears the
|
||||
mark.
|
||||
|
||||
**Collect inputs** — every tech-debt item to register this iteration:
|
||||
|
||||
1. Every UNVERIFIABLE row in the DoD matrix (Phase 3), with its Reactivation
|
||||
Trigger.
|
||||
2. Every ACCEPTED_RISK finding in the code-review final report
|
||||
(`{slug}/reviews/code/final/report`), with its Recommended Reactivation
|
||||
Trigger.
|
||||
3. Every `[OPEN: <short-id>]` marker the Developer left in code this iteration
|
||||
(per implementation checklist POST-6.2).
|
||||
|
||||
If the code-review final report does not exist, warn the user — ACCEPTED_RISK
|
||||
items cannot be captured. This is itself a process gap that must be flagged.
|
||||
|
||||
**Step 1 — De-duplicate against the registry index and promoted issues.**
|
||||
|
||||
1. Read the source ticket's `## TD 登记` comment (create the comment if this
|
||||
is its first row) and match each candidate against existing rows by
|
||||
`TD-NNN` and reactivation trigger. Same-source re-reporting is the
|
||||
anti-pattern this step exists to prevent (the visual-cluster incident: 18
|
||||
fragments from one source under the old keyword matching).
|
||||
2. Query OPEN promoted tech-debt issues for cross-source duplicates:
|
||||
|
||||
```
|
||||
工单 API 检索(见 TERMINOLOGY)
|
||||
(owner/repo 按实例绑定,labels="tech-debt", state="open")
|
||||
```
|
||||
|
||||
**Step 2 — Assign `TD-NNN` via the ledger mutex ([org-internal #3322]).** One script call
|
||||
per batch: `bash script/td-alloc.sh <count = new items> <source-slug>
|
||||
[--ticket N]` returns a contiguous range from the TD allocation ledger
|
||||
(append-only comments, earliest-comment-id wins; the seed comment pins the
|
||||
historical floor). Split the returned range across the Step 3 rows in order.
|
||||
**Any allocation — manual included — must land a `**td-alloc**` comment on
|
||||
the ledger before the registry row is written; hand-computed `max + 1` is
|
||||
forbidden** (the 2026-08-24 three-way collision). On exit 5 (retry
|
||||
exhaustion) abort this phase's filing and retry — never hand-assign. The id is **reserved for life**: promotion reuses it, never
|
||||
renumbers. Run `--check` (reconciliation) here if the last check predates
|
||||
this batch.
|
||||
|
||||
**Step 3 — Append one registry row per new item.** Append to the source
|
||||
ticket's `## TD 登记` comment (no source ticket → the owning Epic's tracker
|
||||
ticket; no Epic → the standing `TD 冷存档` tracker):
|
||||
|
||||
```markdown
|
||||
- [ ] TD-{NNN} · {UNVERIFIABLE | ACCEPTED_RISK | DEFERRED} · {HIGH | MEDIUM | LOW}
|
||||
· {origin chunk-id/iter-N} — {one-line summary}
|
||||
· trigger: {objectively verifiable reactivation condition — never "when ready";
|
||||
if no trigger can be defined this is NOT tech debt and the iteration verdict
|
||||
becomes FAIL}
|
||||
```
|
||||
|
||||
**Step 4 — Cross-link (adapted).** The registry comment already lives on the
|
||||
source issue — the source → debt navigation the old body-edit provided. When
|
||||
filing went to an Epic tracker or the 冷存档 (no source ticket), reference the
|
||||
originating slug in each row so the trail survives.
|
||||
|
||||
**Step 5 — Record the mapping in the verification report.** The report's
|
||||
"Tech Debt" section records `TD-NNN → registry row` (source `#NNNN` +
|
||||
`## TD 登记` comment); promoted items record `TD-NNN → #NNNN` as before.
|
||||
|
||||
**Promotion (认领升票) — when a row is scheduled or picked up.** Create the
|
||||
independent ticket THEN, carrying the reserved `TD-NNN`:
|
||||
|
||||
```
|
||||
gitea_issue__create(owner="Octopus", repo="octopus",
|
||||
title="[{origin}] Tech debt: {short description} (TD-{NNN})",
|
||||
body=<promotion template below>,
|
||||
labels=[tech_debt_label_id, severity_label_id])
|
||||
```
|
||||
|
||||
- **Severity → label** (reuse the existing exclusive Priority set):
|
||||
|
||||
| Severity | Label |
|
||||
| -------- | ----------------- |
|
||||
| HIGH | `Priority/High` |
|
||||
| MEDIUM | `Priority/Medium` |
|
||||
| LOW | `Priority/Low` |
|
||||
|
||||
- **Promotion body template** (the pre-[org-internal #3002] issue template, now used only at
|
||||
promotion):
|
||||
|
||||
```markdown
|
||||
## Parent / 父级
|
||||
|
||||
{#source_issue carrying the ## TD 登记 row}
|
||||
|
||||
## Summary
|
||||
|
||||
{one-paragraph description of the debt}
|
||||
|
||||
| Field | Value |
|
||||
| -------- | ------------------------------------------- |
|
||||
| TD ID | TD-{NNN} (reserved at registration) |
|
||||
| Type | {UNVERIFIABLE \| ACCEPTED_RISK \| DEFERRED} |
|
||||
| Origin | {chunk-id/iter-N/phase or slug} |
|
||||
| Severity | {HIGH \| MEDIUM \| LOW} |
|
||||
|
||||
## Reactivation Trigger
|
||||
|
||||
{from the registry row}
|
||||
|
||||
## 拉动事件 / Pull Event
|
||||
|
||||
{trigger fired: {observed event} | claimed by {who} for {when}}
|
||||
|
||||
## Acceptance Criteria (how to close this issue)
|
||||
|
||||
- [ ] {specific action that resolves the debt}
|
||||
|
||||
## Context
|
||||
|
||||
- Verification report: `{slug}/05-verify-iteration-{N}`
|
||||
- Code review report: `{slug}/reviews/code/final/report` (if ACCEPTED_RISK)
|
||||
```
|
||||
|
||||
- After creating the promoted ticket: tick the registry row (`- [x]`) and
|
||||
append `→ #NNNN` to it.
|
||||
|
||||
If no new tech-debt items were found this iteration, the phase is a no-op —
|
||||
record "0 tech-debt items" in the report and proceed.
|
||||
|
||||
<!-- section:phase-5.55 -->
|
||||
### Phase 5.55 — Baseline-Failure Issue Registration (mandatory before PASS when pre-existing failures exist)
|
||||
|
||||
Pre-existing test failures (BF) are tracked as **root-cause family umbrella
|
||||
tickets** (`core/rules/ticket-lifecycle.md`, [org-internal #3002] G1; precedents [org-internal #2585]
|
||||
umbrella + [org-internal #2925] cluster) — one `BF-NNN` ticket per failure-signature family,
|
||||
labeled `baseline-failure`, with each occurrence's evidence attached as
|
||||
comments. There is no `baseline-failures.md` file and no
|
||||
`{slug}/baseline-failures` wiki page. A pre-existing failure does not block
|
||||
the iteration that _discovered_ it (it pre-dates that work), but it MUST be
|
||||
filed against (or into) a family; an un-filed baseline failure is a process
|
||||
gap and the iteration is NOT Done.
|
||||
|
||||
**Birth triage SLA ([org-internal #3061])**: a BF umbrella is born with `Kind/Bug` (it IS a
|
||||
bug — of the baseline) and must be triaged the SAME DAY it is filed:
|
||||
assigned, scheduled, or explicitly deferred with a reason on the ticket.
|
||||
Untriaged-next-day BF umbrellas are named individually in retro §2.10
|
||||
(compliance %), not averaged away.
|
||||
|
||||
**Collect inputs** — every pre-existing failure to register this iteration:
|
||||
|
||||
1. Every failure classified **pre-existing** in Phase 2.6 (fails on the base
|
||||
branch / last-green commit too).
|
||||
2. Any baseline-run failures noted in the brownfield pre-check (Greenfield vs.
|
||||
Brownfield section).
|
||||
|
||||
**Step 1 — De-duplicate by failure SIGNATURE against existing families (open
|
||||
AND closed), per `core/rules/testing.md`** (de-duplicate BEFORE filing,
|
||||
retro [org-internal #2696]). Query `baseline-failure` issues in ALL states:
|
||||
|
||||
```
|
||||
gitea_issue__list(owner="Octopus", repo="octopus",
|
||||
labels="baseline-failure", state="all")
|
||||
```
|
||||
|
||||
Match each candidate by **failure signature** — the error/assertion signature
|
||||
plus the affected surface, not just `file::test-name` (one root-cause family
|
||||
may span several tests; several tests failing with the same assertion shape
|
||||
are ONE family). On a signature hit, do NOT create a new ticket: attach the
|
||||
new run evidence (run, commit, failing output, sibling tests observed) as a
|
||||
comment on the FAMILY umbrella ticket. Filing a second ticket inside a known
|
||||
root-cause family is the anti-pattern this phase exists to prevent. If a
|
||||
tracked family is now FIXED by this iteration's work, close its umbrella with
|
||||
a comment citing the fixing commit (a bonus, not a requirement). If the query
|
||||
itself errors (API failure — not "no matches"), retry once; on the second
|
||||
failure proceed to file with the literal marker `dedup-unverified` in the
|
||||
umbrella's first evidence comment (query-failure ruling, [org-internal #3383] — fail-open,
|
||||
visible; rationale in `core/rules/ticket-lifecycle.md`).
|
||||
|
||||
**Step 2 — Assign the next `BF-NNN`** per `core/rules/testing.md`
|
||||
§ "Pre-existing test failures must be filed, not silently logged" (the L1 rule
|
||||
owns the repo-wide sequential numbering invariant — `max + 1`, duplicate ids
|
||||
forbidden incl. closed tickets). `BF-NNN` names the FAMILY; the Gitea issue
|
||||
number `#NNNN` is the tracker handle.
|
||||
|
||||
**Step 3 — Create one umbrella ticket per NEW root-cause family.** Only when
|
||||
no existing family matches the signature:
|
||||
|
||||
```
|
||||
gitea_issue__create(owner="Octopus", repo="octopus",
|
||||
title="[{origin}] Baseline failure: {test identifier} (BF-{NNN})",
|
||||
body=<issue body template below>,
|
||||
labels=[baseline_failure_label_id, severity_label_id, kind_bug_label_id])
|
||||
```
|
||||
|
||||
- **Title**: `[{origin}] Baseline failure: {signature summary} (BF-{NNN})`
|
||||
where `{origin}` is `chunk-{id}/iter-{N}` or the bugfix slug, and
|
||||
`{signature summary}` is the family's error/assertion shape (not a single
|
||||
test name — sibling tests observed later join this umbrella as evidence
|
||||
comments).
|
||||
- **Severity → label** (reuse the existing exclusive Priority set; a failing
|
||||
test defaults to at least MEDIUM, HIGH if on a critical path):
|
||||
|
||||
| Severity | Label |
|
||||
| -------- | ----------------- |
|
||||
| HIGH | `Priority/High` |
|
||||
| MEDIUM | `Priority/Medium` |
|
||||
| LOW | `Priority/Low` |
|
||||
|
||||
- Also attach `Kind/Bug` so the failure is discoverable in the bug tracker
|
||||
alongside manually-reported bugs.
|
||||
- **Issue body template**:
|
||||
|
||||
````markdown
|
||||
## Parent / 父级
|
||||
|
||||
{#source_issue, or "no source issue — discovered during iteration baseline"}
|
||||
|
||||
## Summary
|
||||
|
||||
A test was already failing before this iteration's work began. It does not
|
||||
block the discovering iteration but must be tracked to closure.
|
||||
|
||||
| Field | Value |
|
||||
| -------------- | ---------------------------------------------- |
|
||||
| BF ID | BF-{NNN} (family) |
|
||||
| Signature | {error/assertion shape} |
|
||||
| Tests affected | `{file::test-name}`, … (initial members) |
|
||||
| Origin | {chunk-id/iter-N or slug} |
|
||||
| Severity | {HIGH \| MEDIUM \| LOW} |
|
||||
| First observed | {base commit / date the failure reproduces on} |
|
||||
|
||||
## Reproduction
|
||||
|
||||
```
|
||||
git checkout {base commit}
|
||||
(cd <harness-package> && bun test --timeout 120000 {test file}) # or project-equivalent
|
||||
```
|
||||
|
||||
Failing output:
|
||||
|
||||
```
|
||||
{paste the relevant assertion / error}
|
||||
```
|
||||
|
||||
## Acceptance Criteria (how to close this issue)
|
||||
|
||||
- [ ] The named test passes on a clean checkout of the target branch.
|
||||
- [ ] If the test is deleted/renamed, the replacement covers the same
|
||||
behavior and passes.
|
||||
|
||||
## Context
|
||||
|
||||
- Verification report: `{slug}/05-verify-iteration-{N}`
|
||||
````
|
||||
|
||||
**Step 4 — Cross-link to the source issue (mandatory).** Per the
|
||||
issue-cross-linking rule, every baseline-failure issue MUST link back to its
|
||||
source:
|
||||
|
||||
- The issue body already carries `## Parent` (above).
|
||||
- Update the source/parent issue body to reference each new baseline-failure
|
||||
issue by `#NNNN` in its task list (e.g.
|
||||
`- [ ] #NNNN — BF-{NNN} {test identifier}`), so reviewers can navigate from
|
||||
source → failure.
|
||||
|
||||
**Step 5 — Record the mapping in the verification report.** The
|
||||
`BF-NNN → #NNNN` mapping is written ONLY in the Phase 5 verification report's
|
||||
"Baseline Failures" section (and in the issue title itself). There is no local
|
||||
file to update.
|
||||
|
||||
If no new baseline failures were found this iteration, the phase is a no-op —
|
||||
record "0 baseline failures" in the report and proceed.
|
||||
|
||||
<!-- section:phase-5.56 -->
|
||||
### Phase 5.56 — Flaky-Test Issue Registration (mandatory before PASS when flaky tests are unfixed)
|
||||
|
||||
Flaky tests (intermittent pass/fail) are tracked as **root-cause family
|
||||
umbrella tickets** (`core/rules/ticket-lifecycle.md`, [org-internal #3002] G1) — one
|
||||
`FT-NNN` ticket per failure-signature family, labeled `flaky-test`, with each
|
||||
occurrence's evidence (run count, failure rate, commit) attached as comments.
|
||||
A flaky test that is not fixed within this iteration MUST be filed against
|
||||
(or into) a family; otherwise it evaporates at iteration end and the
|
||||
"compare flaky count against baseline" check (TST-2.5) has no persistent
|
||||
register to compare against. Filing does not block the verdict, but an unfixed
|
||||
flaky test left un-filed is a process gap and the iteration is NOT Done.
|
||||
|
||||
**Expiry SLA ([org-internal #3061])**: an FT umbrella is born with `Kind/Testing` and a
|
||||
**fix-or-isolate window** (default 7 days) recorded in its body (isolating =
|
||||
quarantining/skipping the test with the family id in the skip reason, which
|
||||
keeps the register comparable). Past the window without fix or isolation, the
|
||||
umbrella is escalated on the ticket (comment naming the owner); retro §2.10
|
||||
reports fix-or-isolate compliance per cycle.
|
||||
|
||||
**Collect inputs** — every flaky test to register this iteration:
|
||||
|
||||
1. Every flaky test surfaced in Phase 2.1 (intermittent pass/fail across
|
||||
reruns) that was NOT fixed by the Developer this iteration.
|
||||
2. Any flaky test carried over from a prior iteration's report that is still
|
||||
intermittently failing.
|
||||
|
||||
**Step 1 — De-duplicate by failure SIGNATURE against existing families (open
|
||||
AND closed), per `core/rules/testing.md`** (de-duplicate BEFORE filing,
|
||||
retro [org-internal #2696]). Query `flaky-test` issues in ALL states:
|
||||
|
||||
```
|
||||
gitea_issue__list(owner="Octopus", repo="octopus",
|
||||
labels="flaky-test", state="all")
|
||||
```
|
||||
|
||||
Match each candidate by **failure signature** — the flakiness mode (timeout /
|
||||
race / order-dependence / env-leak) plus the affected surface, not just
|
||||
`file::test-name` (one root cause may flake several tests). On a signature
|
||||
hit, do NOT create a new ticket: attach the new run evidence (run count,
|
||||
failure rate, commit, sibling tests) as a comment on the FAMILY umbrella
|
||||
ticket. Filing a second ticket inside a known root-cause family is the
|
||||
anti-pattern this phase exists to prevent. If a tracked family now passes
|
||||
deterministically, close its umbrella citing the fixing commit. If the query
|
||||
itself errors (API failure — not "no matches"), retry once; on the second
|
||||
failure proceed to file with the literal marker `dedup-unverified` in the
|
||||
umbrella's first evidence comment (query-failure ruling, [org-internal #3383] — fail-open,
|
||||
visible; rationale in `core/rules/ticket-lifecycle.md`).
|
||||
|
||||
**Step 2 — Assign the next `FT-NNN`** per `core/rules/testing.md`
|
||||
§ "Flaky tests must be filed, not silently tolerated" (the L1 rule owns the
|
||||
repo-wide sequential numbering invariant — `max + 1`, duplicate ids forbidden
|
||||
incl. closed tickets). `FT-NNN` names the FAMILY.
|
||||
|
||||
**Step 3 — Create one umbrella ticket per NEW root-cause family.** Only when
|
||||
no existing family matches the signature:
|
||||
|
||||
```
|
||||
gitea_issue__create(owner="Octopus", repo="octopus",
|
||||
title="[{origin}] Flaky test: {test identifier} (FT-{NNN})",
|
||||
body=<issue body template below>,
|
||||
labels=[flaky_test_label_id, severity_label_id, kind_testing_label_id])
|
||||
```
|
||||
|
||||
- **Title**: `[{origin}] Flaky test: {signature summary} (FT-{NNN})` — the
|
||||
family's flakiness mode + surface (sibling tests join later as evidence
|
||||
comments, not new tickets).
|
||||
- **Severity** → a flaky test defaults to MEDIUM (HIGH if on a critical path
|
||||
or blocking CI); reuse the exclusive Priority set.
|
||||
- Also attach `Kind/Testing` so it is discoverable in the testing tracker.
|
||||
- **Issue body template**:
|
||||
|
||||
````markdown
|
||||
## Parent / 父级
|
||||
|
||||
{#source_issue, or "no source issue — discovered during iteration verification"}
|
||||
|
||||
## Summary
|
||||
|
||||
A test passes and fails intermittently across runs. It undermines the
|
||||
reliability of the suite and must be stabilized or quarantined.
|
||||
|
||||
| Field | Value |
|
||||
| ------------ | ------------------------- |
|
||||
| FT ID | FT-{NNN} (family) |
|
||||
| Signature | {flakiness mode + surface} |
|
||||
| Tests affected | `{file::test-name}`, … (initial members) |
|
||||
| Origin | {chunk-id/iter-N or slug} |
|
||||
| Severity | {HIGH \| MEDIUM \| LOW} |
|
||||
| Failure rate | {e.g. 3/10 runs} |
|
||||
|
||||
## Reproduction
|
||||
|
||||
```
|
||||
for i in $(seq 1 10); do (cd <harness-package> && bun test --timeout 120000 {test file}) || echo "run $i FAILED"; done
|
||||
```
|
||||
|
||||
## Acceptance Criteria (how to close this issue)
|
||||
|
||||
- [ ] The test passes deterministically across 10 consecutive runs.
|
||||
- [ ] If it cannot be stabilized, it is quarantined (`test.skip` /
|
||||
`test.todo` with a comment citing FT-{NNN}) and a stable replacement
|
||||
is filed as tech-debt (TD-NNN).
|
||||
|
||||
## Context
|
||||
|
||||
- Verification report: `{slug}/05-verify-iteration-{N}`
|
||||
````
|
||||
|
||||
**Step 4 — Cross-link to the source issue (mandatory).** Every flaky-test
|
||||
issue links back to its source via `## Parent`, and the source/parent issue
|
||||
task list references each by `#NNNN`
|
||||
(`- [ ] #NNNN — FT-{NNN} {test identifier}`).
|
||||
|
||||
**Step 5 — Record the mapping in the verification report.** The
|
||||
`FT-NNN → #NNNN` mapping is written ONLY in the Phase 5 report's "Flaky Tests"
|
||||
section (and the issue title). No local file.
|
||||
|
||||
If no unfixed flaky tests exist this iteration, the phase is a no-op — record
|
||||
"0 flaky tests" in the report and proceed.
|
||||
|
||||
<!-- section:phase-5.6 -->
|
||||
### Phase 5.6 — Issue Checklist Sync (final sweep, mandatory before PASS)
|
||||
|
||||
This is the **final** checklist sync — the last of the progressive sync
|
||||
points (requirements exit, design exit, plan exit, each iteration commit, PR
|
||||
creation, review convergence, CI transitions, and here — per the sync-point
|
||||
table in `core/rules/issue-checklist-sync.md`). Earlier syncs may have
|
||||
already checked off completed items; this phase catches everything remaining
|
||||
and ensures no `- [ ]` item is left without an annotation.
|
||||
|
||||
1. **Identify the source issue** per `core/rules/issue-checklist-sync.md`
|
||||
§ "How to sync (each point)" step 1 (find `Closes #N` / `Fixes #N` in the
|
||||
PR body or commit messages). If no source issue exists (e.g. standalone
|
||||
bugfix with no tracking issue), skip this phase.
|
||||
2. **Fetch the issue body** via `工单 API(见 TERMINOLOGY)get` (rule step 2).
|
||||
3. **Map every remaining `- [ ]` checklist item** to one of three states:
|
||||
- **Done** (missed by earlier syncs) → mark `- [x]` and append
|
||||
`_(PR #NNN: <file/component>)_`.
|
||||
- **Deferred** → keep `- [ ]` and append `_(Deferred: TD-NNN <reason>)_`.
|
||||
- **Pending** → keep `- [ ]` and append `_(Pending: <blocker>)_`.
|
||||
4. **Fold the `## 当前状态` live-status section** (if present). Rows that have
|
||||
a checklist counterpart (review, process-ACs) are already reflected as
|
||||
checklist annotations at their sync points. Rows with no checklist
|
||||
counterpart in a non-Epic issue (PR opened/merged) are folded as follow-up
|
||||
evidence on the issue narrative (e.g. `_(PR #NNN merged: <summary>)_` on the
|
||||
item it delivered, or in the report). Once every row is accounted for,
|
||||
remove the section from the issue body.
|
||||
5. **archive-at-close: mark the `## 工件索引` comment archived** (归档动作 — [org-internal #1929]). Issue
|
||||
closing IS the archive-at-close action; it is explicit, not implicit. Edit the index
|
||||
comment in place per `_shared/gitea-write-patterns.md` Pattern 10 Archive-at-close
|
||||
(mechanism — banner + every row's 重读 → ARCHIVE + invariants — is defined there,
|
||||
do not restate; sequence/actor per `rules/issue-checklist-sync.md` § 归档动作).
|
||||
- Skip if no source issue exists.
|
||||
- **Tier 1 run archive** ([org-internal #1988] two-tier artifacts — only if a Tier 1 run
|
||||
workspace exists): if `<runs-root>/{slug}/` exists (a stage in this run
|
||||
produced Tier 1 local artifacts, e.g. review-code findings), archive the
|
||||
run workspace per `core/rules/two-tier-artifacts.md` § Archive-at-close
|
||||
(the L1 rule is authoritative — do NOT restate its steps here).
|
||||
The archived bundle must pass
|
||||
`core/schemas/runs-bundle.schema.json` validation (the generator
|
||||
validates by default; a red exit blocks close).
|
||||
Verify deltas only: skip in milestone/task DAG mode (the aggregator agent
|
||||
performs it at Epic/task-ticket close — see the DAG branch below).
|
||||
6. **Update the issue body** via `工单 API(见 TERMINOLOGY)update` with the annotated
|
||||
checklist. Preserve all non-checklist content unchanged.
|
||||
7. **Verify**: re-read the issue and confirm no `- [ ]` item lacks an
|
||||
annotation. Every unchecked item MUST have a `(Deferred: ...)` or
|
||||
`(Pending: ...)` note explaining why it is not done.
|
||||
8. **Close the issue** (completes the archive-at-close loop): if the flow has
|
||||
no PR (no `Closes #N` on merge), the Verifier closes the issue after PASS
|
||||
approval via `工单 API(见 TERMINOLOGY)update(state="closed")` — the banner date is
|
||||
corrected to the actual close date if it differs from today. If a PR carries
|
||||
`Closes #N`, the merge closes it; no further action.
|
||||
|
||||
If a checklist item cannot be mapped to evidence, deferral, or pending
|
||||
status, the iteration is NOT Done — the item represents untracked scope.
|
||||
### Phase 5.5–5.6 — Issue Filing Protocols (TD registry / baseline / flaky / checklist sync)
|
||||
|
||||
> The four mandatory-before-PASS filing protocols — Phase 5.5 Tech-Debt
|
||||
> registry filing (sprint-mode override), Phase 5.55 baseline-failure
|
||||
> registration, Phase 5.56 flaky-test registration, Phase 5.6 issue
|
||||
> checklist final sweep — live in `reference/issue-filing.md`. Read each at
|
||||
> its boundary during Phase 5; PASS is blocked until all applicable filings
|
||||
> report completion. Phase 5.7 (CI state sync) stays inline below.
|
||||
|
||||
<!-- section:phase-5.7 -->
|
||||
### Phase 5.7 — CI State Transition Sync (progressive)
|
||||
|
||||
Process-type acceptance criteria (e.g. "ci.yml passes N consecutive runs",
|
||||
AC#3 in [org-internal #1668]) have no single moment of completion — their progress lives on
|
||||
AC#3 in [TT-1668]) have no single moment of completion — their progress lives on
|
||||
the issue. The `CI` row in `## 当前状态` is written by the `status-sync` poller
|
||||
(`.gitea/scripts/status-sync-poll.ts`), NOT this skill — do NOT manually
|
||||
`工单 API(见 TERMINOLOGY)update` it. When verification observes a CI state transition
|
||||
@@ -1123,7 +640,7 @@ the issue. The `CI` row in `## 当前状态` is written by the `status-sync` pol
|
||||
process-AC's progress note in place via `工单 API(见 TERMINOLOGY)update` (per the
|
||||
`issue-checklist-sync` L1 rule § Automated sync — the poller owns the CI row;
|
||||
the checklist annotation remains manual). Do NOT wait for Phase 5.6: a
|
||||
transition left unsynced for tens of minutes is exactly the staleness [org-internal #1689]
|
||||
transition left unsynced for tens of minutes is exactly the staleness [TT-1689]
|
||||
targets. Skip if no source issue exists.
|
||||
|
||||
---
|
||||
@@ -1215,181 +732,14 @@ To notify workflow completion, call the `signal_stage_done` tool.
|
||||
---
|
||||
|
||||
<!-- section:dag-branch -->
|
||||
## DAG branch (milestone + task modes)
|
||||
## DAG branch (milestone + task modes) — see `reference/dag-branch.md`
|
||||
|
||||
> This branch OVERRIDES the Preconditions table, Phase 1 read inputs, Phase 5
|
||||
> report index, Phase 5.5 ACCEPTED_RISK source, Phase 5.6 final sweep, and
|
||||
> Phase 6.5 commit gate for a DAG-ticket-pipeline Epic. It applies when the
|
||||
> routed Epic is DAG-shaped: a frozen DAG copy exists at `{epic-slug}/dag` and
|
||||
> the DAG's `task_route.keep_gates` includes `verify`. Legacy iteration verify
|
||||
> (the sections above) remains authoritative for non-DAG iterations. Spec:
|
||||
> `dag-pipeline/spec-05` §5. commit status stays
|
||||
> `pipeline/verify` in both modes.
|
||||
> This branch (milestone mode / task mode / no-milestone Epic gate) lives in
|
||||
> `reference/dag-branch.md`, read it on-demand when the Epic is DAG-shaped:
|
||||
> frozen DAG at `{epic-slug}/dag` + `task_route.keep_gates` includes `verify`.
|
||||
> Legacy iteration verify (the sections above) remains authoritative for
|
||||
> non-DAG iterations. Spec: `dag-pipeline/spec-05` §5.
|
||||
|
||||
### Milestone mode (verify runs on a milestone M when `all_incoming_done_and_green`)
|
||||
|
||||
A milestone node (`type: milestone`) has no implementation work and no ticket;
|
||||
its verify is the integration verification welded at a DAG convergence point
|
||||
(`cross_session_in ≥ 2`). Trigger: the aggregator agent (main
|
||||
session/Orchestrator) detects `all_incoming_done_and_green` — every fan-in
|
||||
source node at its terminal state (task source `done` / milestone source
|
||||
`green`) — and initiates this verify run; the milestone never self-triggers.
|
||||
|
||||
**Precondition replacements** (vs legacy iteration verify):
|
||||
|
||||
| Legacy verify precondition | Milestone-mode replacement |
|
||||
| ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| design-space review converged (`review status --stage design-space` success) | review-dag converged (`review status --stage review-dag` success) |
|
||||
| iteration-plan review converged | REMOVED (DAG has no plan review; the single review-dag gate replaces it) |
|
||||
| legacy iteration plan at `{slug}/04-plan-index` | DAG artifact + milestone fan-in slice (no `04-plan-*` page) |
|
||||
| legacy NFR targets from `{slug}/03-design-06-non-functional-design` | REMOVED (product NFRs live in node AC, handled by per-task review-code) |
|
||||
| upstream roadmap chunk done+verified | all milestone fan-in source nodes at terminal state (task source `done` / milestone source `green`, i.e. `all_incoming_done_and_green`) |
|
||||
| code review converged (`pipeline/review-code` success) | ALL fan-in node tickets review-code PASS + PR merged (implied by `done`) |
|
||||
| code review final report exists | REMOVED (no Epic-level final report; per-node review-code reports live on task tickets) |
|
||||
| carried items from previous iteration closed | REMOVED (vacuous — no iteration) |
|
||||
| `core/checklists/verification.md` accessible | KEEP (unconditional) |
|
||||
| Acceptance criteria exist | from DAG-slice-generated DoD matrix (fan-in node AC + integration/contract-conformance/regression/NFR-coverage items) |
|
||||
| `slug` matches the plan slug | N/A (output naming frozen to `{epic-slug}`) |
|
||||
|
||||
**Phase 1 read inputs** → the DAG slice: read the milestone's fan-in subgraph
|
||||
(fan-in nodes + their cross-session edges + contracts) from the frozen DAG copy
|
||||
`{epic-slug}/dag`, and generate the DoD matrix from it (integration items,
|
||||
contract-conformance items, regression items, NFR-coverage items) instead of
|
||||
reading `04-plan-*` pages.
|
||||
|
||||
**Output naming**: `{epic-slug}/05-verify-milestone-{M-id}` (distinct from
|
||||
iteration verify `05-verify-iteration-{N}`).
|
||||
|
||||
**Phase 5 report index**: append a `VERIFY-M-{M-id}` row to the `## 工件索引`
|
||||
comment with 重读 = `ON-DEMAND` (NOT `ARCHIVE`). The milestone verify does NOT
|
||||
edit the comment directly — it reports the row-payload to the aggregator agent
|
||||
(main session/Orchestrator), which is the SINGLE WRITER appending in place
|
||||
(`工单评论 API(见 TERMINOLOGY)`). `ARCHIVE` is never written by milestone verify
|
||||
(Epic close is the sole archive point).
|
||||
|
||||
**Phase 5.5 ACCEPTED_RISK source**: fan-in node task-ticket review-code reports
|
||||
(located in each task ticket's review annotations / `## 当前状态` review row),
|
||||
not an Epic-level final report. A missing Epic-level final report does NOT
|
||||
trigger the "code-review final report does not exist" warn (that warn is
|
||||
legacy-iteration-only). tech-debt / baseline-failure / flaky-test registration
|
||||
proceeds as usual, sourced from the milestone DoD matrix's regression /
|
||||
baseline-classification results.
|
||||
|
||||
**Phase 5.6 milestone mode** (restricted semantics — skip archive-at-close and
|
||||
issue close):
|
||||
|
||||
1. **Checklist final sweep** only — object = each fan-in task ticket's row 6
|
||||
(`verify里程碑`) + the milestone DoD matrix, NOT the Epic body checklist.
|
||||
Verify each fan-in node's row 6 is checked or annotated
|
||||
`_(Pending: M-{M-id} 未 green)_`. Do NOT flip a still-Pending row 6 — that
|
||||
flip belongs to the aggregator agent (main session/Orchestrator), which
|
||||
performs the node-ticket close action. Write the milestone DoD matrix final
|
||||
sweep to `{epic-slug}/05-verify-milestone-{M-id}`.
|
||||
2. **Do NOT fold/remove any Epic-body `## 当前状态` / `## DAG 状态` section** —
|
||||
milestone verify is read-only on Epic body state.
|
||||
3. **SKIP archive-at-close** (the `## 工件索引` archive banner + row-level
|
||||
`ARCHIVE`) and **SKIP issue close** — both belong to the aggregator agent at
|
||||
Epic close.
|
||||
4. **SKIP Tier 1 run archive** (Phase 5.6 step 5, Tier 1 run archive sub-bullet) — the aggregator agent
|
||||
performs it at Epic close.
|
||||
|
||||
**Milestone verify execution context (pinned)**: run the
|
||||
integration/regression/contract-conformance/NFR suite on a checkout CONTAINING
|
||||
all fan-in nodes' merged code — the aggregator agent syncs main (containing the
|
||||
merged fan-in PRs) into the execution worktree, or builds a temp verify worktree
|
||||
from main HEAD, before triggering; the verify report
|
||||
`{epic-slug}/05-verify-milestone-{M-id}` records the actual execution commit
|
||||
SHA.
|
||||
|
||||
**M→green status transition**: NOT done by milestone verify (read-only on Epic
|
||||
body). The aggregator agent (main session/Orchestrator) reads the verify report
|
||||
and sets the aggregator table M row 状态 = `green`, 重读 = `ON-DEMAND`, and
|
||||
syncs the frozen DAG copy `{epic-slug}/dag` node `status` to `green`.
|
||||
|
||||
**Phase 6.5 milestone mode**: vacuous skip — a milestone has no implementation
|
||||
commit. Commit existence is evidenced by the fan-in node verify PASS + PR
|
||||
merged (already implied by `all_incoming_done_and_green`).
|
||||
|
||||
**Milestone verify FAIL recovery**: FAIL → M `status` = `blocked`. Fix
|
||||
responsibility = the fan-in node owning the failing integration/regression item
|
||||
(the last-done fan-in node's session) or the Epic-level session (DAG author) if
|
||||
un-attributable. Re-run is triggered ONLY by a "fix-landed event" (fix commit
|
||||
merged + CI green, or an explicit re-done report from the owning session) —
|
||||
NOT status polling (done nodes are never reset; `all_incoming_done_and_green`
|
||||
stays true after FAIL). M stays `blocked` until a fix event, then returns to
|
||||
`pending` and verify re-runs. No review-dag re-run unless the fix changes a
|
||||
cross-session contract or the node/edge set.
|
||||
|
||||
### Task mode (verify on a task node ticket, because `task_route.keep_gates` includes `verify`)
|
||||
|
||||
Each task ticket closes only after its own verify run, but legacy verify
|
||||
preconditions do not hold in DAG mode — this node-level branch reuses the
|
||||
`verify` skill with the following node-scoped semantics (so the `verify` gate is
|
||||
not silently downgraded to CI-only).
|
||||
|
||||
**Verification object**: the node's own `acceptance_criteria` → the `test_id`
|
||||
suite (`file-path::test-name` / `MANUAL` / `BENCH:`) all passing fresh + that
|
||||
node's review-code PASS recorded + CI green. NOT milestone fan-in
|
||||
integration/contract/regression items (those are milestone verify's). Spec
|
||||
authority = the node in the frozen DAG copy `{epic-slug}/dag`.
|
||||
|
||||
**Precondition replacements** (task mode — mirror the milestone table, scoped to
|
||||
the node):
|
||||
|
||||
| Legacy verify precondition | Task-mode replacement |
|
||||
| ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- |
|
||||
| design-space review converged | review-dag converged (this Epic already passed the single gate; do NOT re-run it) |
|
||||
| iteration-plan review converged | REMOVED (DAG has no plan review) |
|
||||
| legacy iteration plan at `{slug}/04-plan-index` | the node in the frozen DAG copy `{epic-slug}/dag` (no `04-plan-*` page) |
|
||||
| legacy NFR targets from `{slug}/03-design-06-non-functional-design` | REMOVED (product NFRs live in node AC, handled by per-task review-code) |
|
||||
| upstream roadmap chunk done+verified | this node's cross-session in-edge source nodes at terminal state (task source `done` / milestone source `green`) |
|
||||
| code review converged (`pipeline/review-code` success) | this node's ticket review-code PASS + PR merged |
|
||||
| code review final report exists | REMOVED (this node's review-code report lives on the task ticket) |
|
||||
| carried items from previous iteration closed | REMOVED (vacuous — no iteration) |
|
||||
| `core/checklists/verification.md` accessible | KEEP |
|
||||
| Acceptance criteria exist | from node AC + `test_id` suite |
|
||||
| `slug` matches the plan slug | N/A (Tier 1 run slug = `{epic-slug}-task-{node-id}` — the same node-task run namespace review-code runs in and this mode's archive bundle uses below; the Phase 2 precondition-gate cache read MUST use this slug. Only the wiki output naming stays Epic-scoped: `{epic-slug}/05-verify-task-{node-id}`) |
|
||||
|
||||
**Phase 1 read inputs** → the node's AC + `test_id` suite from the frozen DAG
|
||||
copy `{epic-slug}/dag`, generating the DoD matrix.
|
||||
|
||||
**Output naming**: `{epic-slug}/05-verify-task-{node-id}`.
|
||||
|
||||
**Phase 5 report index**: append a `VERIFY-TASK-{node-id}` row, 重读 =
|
||||
`ON-DEMAND` (NOT `ARCHIVE`), via the aggregator agent as single writer (task
|
||||
verify does not edit the comment directly).
|
||||
|
||||
**Phase 5.5 task mode**: ACCEPTED_RISK source = this node's task-ticket
|
||||
review-code report (no Epic-level final report → no "does not exist" warn).
|
||||
tech-debt / baseline-failure / flaky-test registration proceeds as usual.
|
||||
|
||||
**Phase 5.6 task mode**: only checklist final sweep — object = this ticket's
|
||||
5-row checklist (NOT row 6 `verify里程碑` — row 6 is flipped ONLY by the
|
||||
aggregator agent). SKIP archive-at-close (`## 工件索引` row-level `ARCHIVE`) and
|
||||
issue close (both belong to the aggregator agent). SKIP Tier 1 run archive — the
|
||||
aggregator agent collects it cross-worktree at task-ticket close (archive to
|
||||
`<runs-root>/archive/{epic-slug}-task-{node-id}.json` and commit to the
|
||||
workflow branch). Do NOT fold Epic body status sections.
|
||||
|
||||
**Phase 6.5 task mode**: object = this node ticket's commit; semantics = "node
|
||||
implementation commit exists". Baseline = the task worktree's creation-commit
|
||||
SHA (`git log {creation-SHA}..HEAD`), NOT a generic base-branch (post-merge
|
||||
there are no new commits vs base). The task worktree is retained until ticket
|
||||
close (the aggregator agent removes it after collecting task-level Tier 1
|
||||
archive); the task session must NOT remove its own worktree.
|
||||
|
||||
**commit status**: still `pipeline/verify` in both modes.
|
||||
|
||||
### No-milestone DAG Epic-level verify gate
|
||||
|
||||
When the routed Epic's DAG has NO milestone (no `cross_session_in ≥ 2`
|
||||
convergence point), the Epic-level `keep_gates: verify` is satisfied
|
||||
AGGREGATELY by all task-ticket verify runs (each with commit status
|
||||
`pipeline/verify` success) — NO independent Epic-level verify run, NO
|
||||
`{epic-slug}/05-verify-milestone-{M-id}` artifact, NO `VERIFY-M-{M-id}` index
|
||||
row. The Epic close condition degenerates to "all task nodes `done`".
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
> Extracted from verify/SKILL.md (section:dag-branch) — moved verbatim; read
|
||||
> on-demand ONLY when the routed Epic is DAG-shaped (frozen DAG at
|
||||
> `{epic-slug}/dag` and `task_route.keep_gates` includes `verify`).
|
||||
|
||||
<!-- section:dag-branch -->
|
||||
## DAG branch (milestone + task modes)
|
||||
|
||||
> This branch OVERRIDES the Preconditions table, Phase 1 read inputs, Phase 5
|
||||
> report index, Phase 5.5 ACCEPTED_RISK source, Phase 5.6 final sweep, and
|
||||
> Phase 6.5 commit gate for a DAG-ticket-pipeline Epic. It applies when the
|
||||
> routed Epic is DAG-shaped: a frozen DAG copy exists at `{epic-slug}/dag` and
|
||||
> the DAG's `task_route.keep_gates` includes `verify`. Legacy iteration verify
|
||||
> (the sections above) remains authoritative for non-DAG iterations. Spec:
|
||||
> `dag-pipeline/spec-05` §5. commit status stays
|
||||
> `pipeline/verify` in both modes.
|
||||
|
||||
### Milestone mode (verify runs on a milestone M when `all_incoming_done_and_green`)
|
||||
|
||||
A milestone node (`type: milestone`) has no implementation work and no ticket;
|
||||
its verify is the integration verification welded at a DAG convergence point
|
||||
(`cross_session_in ≥ 2`). Trigger: the aggregator agent (main
|
||||
session/Orchestrator) detects `all_incoming_done_and_green` — every fan-in
|
||||
source node at its terminal state (task source `done` / milestone source
|
||||
`green`) — and initiates this verify run; the milestone never self-triggers.
|
||||
|
||||
**Precondition replacements** (vs legacy iteration verify):
|
||||
|
||||
| Legacy verify precondition | Milestone-mode replacement |
|
||||
| ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| design-space review converged (`review status --stage design-space` success) | review-dag converged (`review status --stage review-dag` success) |
|
||||
| iteration-plan review converged | REMOVED (DAG has no plan review; the single review-dag gate replaces it) |
|
||||
| legacy iteration plan at `{slug}/04-plan-index` | DAG artifact + milestone fan-in slice (no `04-plan-*` page) |
|
||||
| legacy NFR targets from `{slug}/03-design-06-non-functional-design` | REMOVED (product NFRs live in node AC, handled by per-task review-code) |
|
||||
| upstream roadmap chunk done+verified | all milestone fan-in source nodes at terminal state (task source `done` / milestone source `green`, i.e. `all_incoming_done_and_green`) |
|
||||
| code review converged (`pipeline/review-code` success) | ALL fan-in node tickets review-code PASS + PR merged (implied by `done`) |
|
||||
| code review final report exists | REMOVED (no Epic-level final report; per-node review-code reports live on task tickets) |
|
||||
| carried items from previous iteration closed | REMOVED (vacuous — no iteration) |
|
||||
| `core/checklists/verification.md` accessible | KEEP (unconditional) |
|
||||
| Acceptance criteria exist | from DAG-slice-generated DoD matrix (fan-in node AC + integration/contract-conformance/regression/NFR-coverage items) |
|
||||
| `slug` matches the plan slug | N/A (output naming frozen to `{epic-slug}`) |
|
||||
|
||||
**Phase 1 read inputs** → the DAG slice: read the milestone's fan-in subgraph
|
||||
(fan-in nodes + their cross-session edges + contracts) from the frozen DAG copy
|
||||
`{epic-slug}/dag`, and generate the DoD matrix from it (integration items,
|
||||
contract-conformance items, regression items, NFR-coverage items) instead of
|
||||
reading `04-plan-*` pages.
|
||||
|
||||
**Output naming**: `{epic-slug}/05-verify-milestone-{M-id}` (distinct from
|
||||
iteration verify `05-verify-iteration-{N}`).
|
||||
|
||||
**Phase 5 report index**: append a `VERIFY-M-{M-id}` row to the `## 工件索引`
|
||||
comment with 重读 = `ON-DEMAND` (NOT `ARCHIVE`). The milestone verify does NOT
|
||||
edit the comment directly — it reports the row-payload to the aggregator agent
|
||||
(main session/Orchestrator), which is the SINGLE WRITER appending in place
|
||||
(`工单评论 API(见 TERMINOLOGY)`). `ARCHIVE` is never written by milestone verify
|
||||
(Epic close is the sole archive point).
|
||||
|
||||
**Phase 5.5 ACCEPTED_RISK source**: fan-in node task-ticket review-code reports
|
||||
(located in each task ticket's review annotations / `## 当前状态` review row),
|
||||
not an Epic-level final report. A missing Epic-level final report does NOT
|
||||
trigger the "code-review final report does not exist" warn (that warn is
|
||||
legacy-iteration-only). tech-debt / baseline-failure / flaky-test registration
|
||||
proceeds as usual, sourced from the milestone DoD matrix's regression /
|
||||
baseline-classification results.
|
||||
|
||||
**Phase 5.6 milestone mode** (restricted semantics — skip archive-at-close and
|
||||
issue close):
|
||||
|
||||
1. **Checklist final sweep** only — object = each fan-in task ticket's row 6
|
||||
(`verify里程碑`) + the milestone DoD matrix, NOT the Epic body checklist.
|
||||
Verify each fan-in node's row 6 is checked or annotated
|
||||
`_(Pending: M-{M-id} 未 green)_`. Do NOT flip a still-Pending row 6 — that
|
||||
flip belongs to the aggregator agent (main session/Orchestrator), which
|
||||
performs the node-ticket close action. Write the milestone DoD matrix final
|
||||
sweep to `{epic-slug}/05-verify-milestone-{M-id}`.
|
||||
2. **Do NOT fold/remove any Epic-body `## 当前状态` / `## DAG 状态` section** —
|
||||
milestone verify is read-only on Epic body state.
|
||||
3. **SKIP archive-at-close** (the `## 工件索引` archive banner + row-level
|
||||
`ARCHIVE`) and **SKIP issue close** — both belong to the aggregator agent at
|
||||
Epic close.
|
||||
4. **SKIP Tier 1 run archive** (Phase 5.6 step 5, Tier 1 run archive sub-bullet) — the aggregator agent
|
||||
performs it at Epic close.
|
||||
|
||||
**Milestone verify execution context (pinned)**: run the
|
||||
integration/regression/contract-conformance/NFR suite on a checkout CONTAINING
|
||||
all fan-in nodes' merged code — the aggregator agent syncs main (containing the
|
||||
merged fan-in PRs) into the execution worktree, or builds a temp verify worktree
|
||||
from main HEAD, before triggering; the verify report
|
||||
`{epic-slug}/05-verify-milestone-{M-id}` records the actual execution commit
|
||||
SHA.
|
||||
|
||||
**M→green status transition**: NOT done by milestone verify (read-only on Epic
|
||||
body). The aggregator agent (main session/Orchestrator) reads the verify report
|
||||
and sets the aggregator table M row 状态 = `green`, 重读 = `ON-DEMAND`, and
|
||||
syncs the frozen DAG copy `{epic-slug}/dag` node `status` to `green`.
|
||||
|
||||
**Phase 6.5 milestone mode**: vacuous skip — a milestone has no implementation
|
||||
commit. Commit existence is evidenced by the fan-in node verify PASS + PR
|
||||
merged (already implied by `all_incoming_done_and_green`).
|
||||
|
||||
**Milestone verify FAIL recovery**: FAIL → M `status` = `blocked`. Fix
|
||||
responsibility = the fan-in node owning the failing integration/regression item
|
||||
(the last-done fan-in node's session) or the Epic-level session (DAG author) if
|
||||
un-attributable. Re-run is triggered ONLY by a "fix-landed event" (fix commit
|
||||
merged + CI green, or an explicit re-done report from the owning session) —
|
||||
NOT status polling (done nodes are never reset; `all_incoming_done_and_green`
|
||||
stays true after FAIL). M stays `blocked` until a fix event, then returns to
|
||||
`pending` and verify re-runs. No review-dag re-run unless the fix changes a
|
||||
cross-session contract or the node/edge set.
|
||||
|
||||
### Task mode (verify on a task node ticket, because `task_route.keep_gates` includes `verify`)
|
||||
|
||||
Each task ticket closes only after its own verify run, but legacy verify
|
||||
preconditions do not hold in DAG mode — this node-level branch reuses the
|
||||
`verify` skill with the following node-scoped semantics (so the `verify` gate is
|
||||
not silently downgraded to CI-only).
|
||||
|
||||
**Verification object**: the node's own `acceptance_criteria` → the `test_id`
|
||||
suite (`file-path::test-name` / `MANUAL` / `BENCH:`) all passing fresh + that
|
||||
node's review-code PASS recorded + CI green. NOT milestone fan-in
|
||||
integration/contract/regression items (those are milestone verify's). Spec
|
||||
authority = the node in the frozen DAG copy `{epic-slug}/dag`.
|
||||
|
||||
**Precondition replacements** (task mode — mirror the milestone table, scoped to
|
||||
the node):
|
||||
|
||||
| Legacy verify precondition | Task-mode replacement |
|
||||
| ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- |
|
||||
| design-space review converged | review-dag converged (this Epic already passed the single gate; do NOT re-run it) |
|
||||
| iteration-plan review converged | REMOVED (DAG has no plan review) |
|
||||
| legacy iteration plan at `{slug}/04-plan-index` | the node in the frozen DAG copy `{epic-slug}/dag` (no `04-plan-*` page) |
|
||||
| legacy NFR targets from `{slug}/03-design-06-non-functional-design` | REMOVED (product NFRs live in node AC, handled by per-task review-code) |
|
||||
| upstream roadmap chunk done+verified | this node's cross-session in-edge source nodes at terminal state (task source `done` / milestone source `green`) |
|
||||
| code review converged (`pipeline/review-code` success) | this node's ticket review-code PASS + PR merged |
|
||||
| code review final report exists | REMOVED (this node's review-code report lives on the task ticket) |
|
||||
| carried items from previous iteration closed | REMOVED (vacuous — no iteration) |
|
||||
| `core/checklists/verification.md` accessible | KEEP |
|
||||
| Acceptance criteria exist | from node AC + `test_id` suite |
|
||||
| `slug` matches the plan slug | N/A (Tier 1 run slug = `{epic-slug}-task-{node-id}` — the same node-task run namespace review-code runs in and this mode's archive bundle uses below; the Phase 2 precondition-gate cache read MUST use this slug. Only the wiki output naming stays Epic-scoped: `{epic-slug}/05-verify-task-{node-id}`) |
|
||||
|
||||
**Phase 1 read inputs** → the node's AC + `test_id` suite from the frozen DAG
|
||||
copy `{epic-slug}/dag`, generating the DoD matrix.
|
||||
|
||||
**Output naming**: `{epic-slug}/05-verify-task-{node-id}`.
|
||||
|
||||
**Phase 5 report index**: append a `VERIFY-TASK-{node-id}` row, 重读 =
|
||||
`ON-DEMAND` (NOT `ARCHIVE`), via the aggregator agent as single writer (task
|
||||
verify does not edit the comment directly).
|
||||
|
||||
**Phase 5.5 task mode**: ACCEPTED_RISK source = this node's task-ticket
|
||||
review-code report (no Epic-level final report → no "does not exist" warn).
|
||||
tech-debt / baseline-failure / flaky-test registration proceeds as usual.
|
||||
|
||||
**Phase 5.6 task mode**: only checklist final sweep — object = this ticket's
|
||||
5-row checklist (NOT row 6 `verify里程碑` — row 6 is flipped ONLY by the
|
||||
aggregator agent). SKIP archive-at-close (`## 工件索引` row-level `ARCHIVE`) and
|
||||
issue close (both belong to the aggregator agent). SKIP Tier 1 run archive — the
|
||||
aggregator agent collects it cross-worktree at task-ticket close (archive to
|
||||
`<runs-root>/archive/{epic-slug}-task-{node-id}.json` and commit to the
|
||||
workflow branch). Do NOT fold Epic body status sections.
|
||||
|
||||
**Phase 6.5 task mode**: object = this node ticket's commit; semantics = "node
|
||||
implementation commit exists". Baseline = the task worktree's creation-commit
|
||||
SHA (`git log {creation-SHA}..HEAD`), NOT a generic base-branch (post-merge
|
||||
there are no new commits vs base). The task worktree is retained until ticket
|
||||
close (the aggregator agent removes it after collecting task-level Tier 1
|
||||
archive); the task session must NOT remove its own worktree.
|
||||
|
||||
**commit status**: still `pipeline/verify` in both modes.
|
||||
|
||||
### No-milestone DAG Epic-level verify gate
|
||||
|
||||
When the routed Epic's DAG has NO milestone (no `cross_session_in ≥ 2`
|
||||
convergence point), the Epic-level `keep_gates: verify` is satisfied
|
||||
AGGREGATELY by all task-ticket verify runs (each with commit status
|
||||
`pipeline/verify` success) — NO independent Epic-level verify run, NO
|
||||
`{epic-slug}/05-verify-milestone-{M-id}` artifact, NO `VERIFY-M-{M-id}` index
|
||||
row. The Epic close condition degenerates to "all task nodes `done`".
|
||||
|
||||
---
|
||||
@@ -0,0 +1,495 @@
|
||||
> Extracted from verify/SKILL.md (phase 5.5 / 5.55 / 5.56 / 5.6) — moved
|
||||
> verbatim; read on-demand during Phase 5 execution, before PASS. Each phase
|
||||
> is mandatory-before-PASS in its trigger condition; the main flow stops at
|
||||
> each boundary until the referenced protocol reports completion.
|
||||
|
||||
<!-- section:phase-5.5 -->
|
||||
### Phase 5.5 — Tech Debt Registry Filing (mandatory before PASS)
|
||||
|
||||
Tech debt is filed **registry-first** (`core/rules/ticket-lifecycle.md`,
|
||||
[TT-3002] G1): new items become ROWS in the source ticket's `## TD 登记` comment;
|
||||
an independent ticket is created only at **promotion** (claim/schedule). There
|
||||
is no `tech-debt.md` file and no `{slug}/tech-debt` wiki page — both remain
|
||||
retired. The registry preserves the three guarantees of the old
|
||||
one-issue-per-item model: visible (the comment lives on a tracker ticket),
|
||||
individually closeable (row-level checkbox), de-duplicated across sessions
|
||||
(the TD index is stronger than title-keyword matching).
|
||||
|
||||
**Sprint-mode override ([TT-3002] G5/[TT-3007])**: read `filing.sprint-mode` from
|
||||
`<instance-root>/workflow-routing.yaml` at the START of this phase (no caching). When
|
||||
`true`, ALL severities file registry-only — registration rows are written as
|
||||
normal (severity included, nothing lost) but promotion to standalone tickets
|
||||
is FROZEN until the switch returns to `false`. Rationale: the 2026-08-12
|
||||
sprint zeroed fix capacity while filing kept running (the 125-fragment
|
||||
backlog's direct trigger); an explicit debt-side downshift beats hoping for
|
||||
discipline. BF/FT phases 5.55/5.56 are NOT covered by this switch — failure
|
||||
evidence must stay immediately visible. Flipping the switch is a human
|
||||
decision recorded on the sprint tracker; semantics in
|
||||
`rules/workflow-routing.md` §立案降档.
|
||||
|
||||
**Adjacency quota ([TT-3002] G3/[TT-3005])**: while collecting inputs, also check the
|
||||
AREAS this iteration touched (packages/modules with commits this iteration).
|
||||
If the source tickets for those areas carry applicable `## TD 登记` rows, at
|
||||
least ONE row must be taken along and disposed this iteration (fixed, or
|
||||
explicitly re-deferred with a reason — silence is not a disposition). Record
|
||||
`consumed X / applicable Y` (or `0 applicable`) in the TD report section;
|
||||
verification checklist §8.4 cross-checks it against the run's debt-quota
|
||||
record (historically the roadmap's per-chunk debt-quota line). This gives debt digestion a steady capacity source tied to
|
||||
touch, not to cleanup campaigns.
|
||||
|
||||
**Promotion quota + pull event ([TT-3061])**: promotion to a standalone ticket
|
||||
requires (a) a **pull event** — the row's Reactivation Trigger fired (state
|
||||
the observed event) OR a named claimer/schedule; "it seemed important" is not
|
||||
a pull event — recorded in the promotion body's `## 拉动事件 / Pull Event`
|
||||
section; and (b) the origin module's OPEN promoted-TD count is below the
|
||||
quota (**default 10** — counted **per origin module**: resolve the row's
|
||||
module from the ticket body's `Origin` field, then count that module's OPEN
|
||||
`tech-debt` tickets; retro §2.10 reports breaches). At or above quota →
|
||||
register-only until the count drops; before each Phase 5.5 promotion
|
||||
re-check the owning module's count, and a row whose module is at or above
|
||||
quota is NOT promoted — defer it and annotate the registry row with
|
||||
`quota-held` (re-checked on the next verify run, retro 2026-08-21). A row
|
||||
marked `[COLD]` by retrospective §2.10
|
||||
(unclaimed >3 retro cycles) promotes only after the pull event clears the
|
||||
mark.
|
||||
|
||||
**Collect inputs** — every tech-debt item to register this iteration:
|
||||
|
||||
1. Every UNVERIFIABLE row in the DoD matrix (Phase 3), with its Reactivation
|
||||
Trigger.
|
||||
2. Every ACCEPTED_RISK finding in the code-review final report
|
||||
(`{slug}/reviews/code/final/report`), with its Recommended Reactivation
|
||||
Trigger.
|
||||
3. Every `[OPEN: <short-id>]` marker the Developer left in code this iteration
|
||||
(per implementation checklist POST-6.2).
|
||||
|
||||
If the code-review final report does not exist, warn the user — ACCEPTED_RISK
|
||||
items cannot be captured. This is itself a process gap that must be flagged.
|
||||
|
||||
**Step 1 — De-duplicate against the registry index and promoted issues.**
|
||||
|
||||
1. Read the source ticket's `## TD 登记` comment (create the comment if this
|
||||
is its first row) and match each candidate against existing rows by
|
||||
`TD-NNN` and reactivation trigger. Same-source re-reporting is the
|
||||
anti-pattern this step exists to prevent (the visual-cluster incident: 18
|
||||
fragments from one source under the old keyword matching).
|
||||
2. Query OPEN promoted tech-debt issues for cross-source duplicates:
|
||||
|
||||
```
|
||||
工单 API 检索(见 TERMINOLOGY)
|
||||
(owner/repo 按实例绑定,labels="tech-debt", state="open")
|
||||
```
|
||||
|
||||
**Step 2 — Assign `TD-NNN` via the ledger mutex ([TT-3322]).** One script call
|
||||
per batch: `bash script/td-alloc.sh <count = new items> <source-slug>
|
||||
[--ticket N]` returns a contiguous range from the TD allocation ledger
|
||||
(append-only comments, earliest-comment-id wins; the seed comment pins the
|
||||
historical floor). Split the returned range across the Step 3 rows in order.
|
||||
**Any allocation — manual included — must land a `**td-alloc**` comment on
|
||||
the ledger before the registry row is written; hand-computed `max + 1` is
|
||||
forbidden** (the 2026-08-24 three-way collision). On exit 5 (retry
|
||||
exhaustion) abort this phase's filing and retry — never hand-assign. The id is **reserved for life**: promotion reuses it, never
|
||||
renumbers. Run `--check` (reconciliation) here if the last check predates
|
||||
this batch.
|
||||
|
||||
**Step 3 — Append one registry row per new item.** Append to the source
|
||||
ticket's `## TD 登记` comment (no source ticket → the owning Epic's tracker
|
||||
ticket; no Epic → the standing `TD 冷存档` tracker):
|
||||
|
||||
```markdown
|
||||
- [ ] TD-{NNN} · {UNVERIFIABLE | ACCEPTED_RISK | DEFERRED} · {HIGH | MEDIUM | LOW}
|
||||
· {origin chunk-id/iter-N} — {one-line summary}
|
||||
· trigger: {objectively verifiable reactivation condition — never "when ready";
|
||||
if no trigger can be defined this is NOT tech debt and the iteration verdict
|
||||
becomes FAIL}
|
||||
```
|
||||
|
||||
**Step 4 — Cross-link (adapted).** The registry comment already lives on the
|
||||
source issue — the source → debt navigation the old body-edit provided. When
|
||||
filing went to an Epic tracker or the 冷存档 (no source ticket), reference the
|
||||
originating slug in each row so the trail survives.
|
||||
|
||||
**Step 5 — Record the mapping in the verification report.** The report's
|
||||
"Tech Debt" section records `TD-NNN → registry row` (source `#NNNN` +
|
||||
`## TD 登记` comment); promoted items record `TD-NNN → #NNNN` as before.
|
||||
|
||||
**Promotion (认领升票) — when a row is scheduled or picked up.** Create the
|
||||
independent ticket THEN, carrying the reserved `TD-NNN`:
|
||||
|
||||
```
|
||||
POST <gitea-base-url>/api/v1/repos/Octopus/octopus/issues
|
||||
body: {"title":"[{origin}] Tech debt: {short description} (TD-{NNN})",
|
||||
"body":<promotion template below>,
|
||||
"labels":[tech_debt_label_id, severity_label_id]}
|
||||
```
|
||||
|
||||
- **Severity → label** (reuse the existing exclusive Priority set):
|
||||
|
||||
| Severity | Label |
|
||||
| -------- | ----------------- |
|
||||
| HIGH | `Priority/High` |
|
||||
| MEDIUM | `Priority/Medium` |
|
||||
| LOW | `Priority/Low` |
|
||||
|
||||
- **Promotion body template** (the pre-[TT-3002] issue template, now used only at
|
||||
promotion):
|
||||
|
||||
```markdown
|
||||
## Parent / 父级
|
||||
|
||||
{#source_issue carrying the ## TD 登记 row}
|
||||
|
||||
## Summary
|
||||
|
||||
{one-paragraph description of the debt}
|
||||
|
||||
| Field | Value |
|
||||
| -------- | ------------------------------------------- |
|
||||
| TD ID | TD-{NNN} (reserved at registration) |
|
||||
| Type | {UNVERIFIABLE \| ACCEPTED_RISK \| DEFERRED} |
|
||||
| Origin | {chunk-id/iter-N/phase or slug} |
|
||||
| Severity | {HIGH \| MEDIUM \| LOW} |
|
||||
|
||||
## Reactivation Trigger
|
||||
|
||||
{from the registry row}
|
||||
|
||||
## 拉动事件 / Pull Event
|
||||
|
||||
{trigger fired: {observed event} | claimed by {who} for {when}}
|
||||
|
||||
## Acceptance Criteria (how to close this issue)
|
||||
|
||||
- [ ] {specific action that resolves the debt}
|
||||
|
||||
## Context
|
||||
|
||||
- Verification report: `{slug}/05-verify-iteration-{N}`
|
||||
- Code review report: `{slug}/reviews/code/final/report` (if ACCEPTED_RISK)
|
||||
```
|
||||
|
||||
- After creating the promoted ticket: tick the registry row (`- [x]`) and
|
||||
append `→ #NNNN` to it.
|
||||
|
||||
If no new tech-debt items were found this iteration, the phase is a no-op —
|
||||
record "0 tech-debt items" in the report and proceed.
|
||||
|
||||
<!-- section:phase-5.55 -->
|
||||
### Phase 5.55 — Baseline-Failure Issue Registration (mandatory before PASS when pre-existing failures exist)
|
||||
|
||||
Pre-existing test failures (BF) are tracked as **root-cause family umbrella
|
||||
tickets** (`core/rules/ticket-lifecycle.md`, [TT-3002] G1; precedents [TT-2585]
|
||||
umbrella + [TT-2925] cluster) — one `BF-NNN` ticket per failure-signature family,
|
||||
labeled `baseline-failure`, with each occurrence's evidence attached as
|
||||
comments. There is no `baseline-failures.md` file and no
|
||||
`{slug}/baseline-failures` wiki page. A pre-existing failure does not block
|
||||
the iteration that _discovered_ it (it pre-dates that work), but it MUST be
|
||||
filed against (or into) a family; an un-filed baseline failure is a process
|
||||
gap and the iteration is NOT Done.
|
||||
|
||||
**Birth triage SLA ([TT-3061])**: a BF umbrella is born with `Kind/Bug` (it IS a
|
||||
bug — of the baseline) and must be triaged the SAME DAY it is filed:
|
||||
assigned, scheduled, or explicitly deferred with a reason on the ticket.
|
||||
Untriaged-next-day BF umbrellas are named individually in retro §2.10
|
||||
(compliance %), not averaged away.
|
||||
|
||||
**Collect inputs** — every pre-existing failure to register this iteration:
|
||||
|
||||
1. Every failure classified **pre-existing** in Phase 2.6 (fails on the base
|
||||
branch / last-green commit too).
|
||||
2. Any baseline-run failures noted in the brownfield pre-check (Greenfield vs.
|
||||
Brownfield section).
|
||||
|
||||
**Step 1 — De-duplicate by failure SIGNATURE against existing families (open
|
||||
AND closed), per `core/rules/testing.md`** (de-duplicate BEFORE filing,
|
||||
retro [TT-2696]). Query `baseline-failure` issues in ALL states:
|
||||
|
||||
```
|
||||
GET <gitea-base-url>/api/v1/repos/Octopus/octopus/issues?labels=baseline-failure&state=all&page=N&limit=50
|
||||
```
|
||||
|
||||
Match each candidate by **failure signature** — the error/assertion signature
|
||||
plus the affected surface, not just `file::test-name` (one root-cause family
|
||||
may span several tests; several tests failing with the same assertion shape
|
||||
are ONE family). On a signature hit, do NOT create a new ticket: attach the
|
||||
new run evidence (run, commit, failing output, sibling tests observed) as a
|
||||
comment on the FAMILY umbrella ticket. Filing a second ticket inside a known
|
||||
root-cause family is the anti-pattern this phase exists to prevent. If a
|
||||
tracked family is now FIXED by this iteration's work, close its umbrella with
|
||||
a comment citing the fixing commit (a bonus, not a requirement). If the query
|
||||
itself errors (API failure — not "no matches"), retry once; on the second
|
||||
failure proceed to file with the literal marker `dedup-unverified` in the
|
||||
umbrella's first evidence comment (query-failure ruling, [TT-3383] — fail-open,
|
||||
visible; rationale in `core/rules/ticket-lifecycle.md`).
|
||||
|
||||
**Step 2 — Assign the next `BF-NNN`** per `core/rules/testing.md`
|
||||
§ "Pre-existing test failures must be filed, not silently logged" (the L1 rule
|
||||
owns the repo-wide sequential numbering invariant — `max + 1`, duplicate ids
|
||||
forbidden incl. closed tickets). `BF-NNN` names the FAMILY; the Gitea issue
|
||||
number `#NNNN` is the tracker handle.
|
||||
|
||||
**Step 3 — Create one umbrella ticket per NEW root-cause family.** Only when
|
||||
no existing family matches the signature:
|
||||
|
||||
```
|
||||
POST <gitea-base-url>/api/v1/repos/Octopus/octopus/issues
|
||||
body: {"title":"[{origin}] Baseline failure: {test identifier} (BF-{NNN})",
|
||||
"body":<issue body template below>,
|
||||
"labels":[baseline_failure_label_id, severity_label_id, kind_bug_label_id]}
|
||||
```
|
||||
|
||||
- **Title**: `[{origin}] Baseline failure: {signature summary} (BF-{NNN})`
|
||||
where `{origin}` is `chunk-{id}/iter-{N}` or the bugfix slug, and
|
||||
`{signature summary}` is the family's error/assertion shape (not a single
|
||||
test name — sibling tests observed later join this umbrella as evidence
|
||||
comments).
|
||||
- **Severity → label** (reuse the existing exclusive Priority set; a failing
|
||||
test defaults to at least MEDIUM, HIGH if on a critical path):
|
||||
|
||||
| Severity | Label |
|
||||
| -------- | ----------------- |
|
||||
| HIGH | `Priority/High` |
|
||||
| MEDIUM | `Priority/Medium` |
|
||||
| LOW | `Priority/Low` |
|
||||
|
||||
- Also attach `Kind/Bug` so the failure is discoverable in the bug tracker
|
||||
alongside manually-reported bugs.
|
||||
- **Issue body template**:
|
||||
|
||||
````markdown
|
||||
## Parent / 父级
|
||||
|
||||
{#source_issue, or "no source issue — discovered during iteration baseline"}
|
||||
|
||||
## Summary
|
||||
|
||||
A test was already failing before this iteration's work began. It does not
|
||||
block the discovering iteration but must be tracked to closure.
|
||||
|
||||
| Field | Value |
|
||||
| -------------- | ---------------------------------------------- |
|
||||
| BF ID | BF-{NNN} (family) |
|
||||
| Signature | {error/assertion shape} |
|
||||
| Tests affected | `{file::test-name}`, … (initial members) |
|
||||
| Origin | {chunk-id/iter-N or slug} |
|
||||
| Severity | {HIGH \| MEDIUM \| LOW} |
|
||||
| First observed | {base commit / date the failure reproduces on} |
|
||||
|
||||
## Reproduction
|
||||
|
||||
```
|
||||
git checkout {base commit}
|
||||
(cd <harness-package> && bun test --timeout 120000 {test file}) # or project-equivalent
|
||||
```
|
||||
|
||||
Failing output:
|
||||
|
||||
```
|
||||
{paste the relevant assertion / error}
|
||||
```
|
||||
|
||||
## Acceptance Criteria (how to close this issue)
|
||||
|
||||
- [ ] The named test passes on a clean checkout of the target branch.
|
||||
- [ ] If the test is deleted/renamed, the replacement covers the same
|
||||
behavior and passes.
|
||||
|
||||
## Context
|
||||
|
||||
- Verification report: `{slug}/05-verify-iteration-{N}`
|
||||
````
|
||||
|
||||
**Step 4 — Cross-link to the source issue (mandatory).** Per the
|
||||
issue-cross-linking rule, every baseline-failure issue MUST link back to its
|
||||
source:
|
||||
|
||||
- The issue body already carries `## Parent` (above).
|
||||
- Update the source/parent issue body to reference each new baseline-failure
|
||||
issue by `#NNNN` in its task list (e.g.
|
||||
`- [ ] #NNNN — BF-{NNN} {test identifier}`), so reviewers can navigate from
|
||||
source → failure.
|
||||
|
||||
**Step 5 — Record the mapping in the verification report.** The
|
||||
`BF-NNN → #NNNN` mapping is written ONLY in the Phase 5 verification report's
|
||||
"Baseline Failures" section (and in the issue title itself). There is no local
|
||||
file to update.
|
||||
|
||||
If no new baseline failures were found this iteration, the phase is a no-op —
|
||||
record "0 baseline failures" in the report and proceed.
|
||||
|
||||
<!-- section:phase-5.56 -->
|
||||
### Phase 5.56 — Flaky-Test Issue Registration (mandatory before PASS when flaky tests are unfixed)
|
||||
|
||||
Flaky tests (intermittent pass/fail) are tracked as **root-cause family
|
||||
umbrella tickets** (`core/rules/ticket-lifecycle.md`, [TT-3002] G1) — one
|
||||
`FT-NNN` ticket per failure-signature family, labeled `flaky-test`, with each
|
||||
occurrence's evidence (run count, failure rate, commit) attached as comments.
|
||||
A flaky test that is not fixed within this iteration MUST be filed against
|
||||
(or into) a family; otherwise it evaporates at iteration end and the
|
||||
"compare flaky count against baseline" check (TST-2.5) has no persistent
|
||||
register to compare against. Filing does not block the verdict, but an unfixed
|
||||
flaky test left un-filed is a process gap and the iteration is NOT Done.
|
||||
|
||||
**Expiry SLA ([TT-3061])**: an FT umbrella is born with `Kind/Testing` and a
|
||||
**fix-or-isolate window** (default 7 days) recorded in its body (isolating =
|
||||
quarantining/skipping the test with the family id in the skip reason, which
|
||||
keeps the register comparable). Past the window without fix or isolation, the
|
||||
umbrella is escalated on the ticket (comment naming the owner); retro §2.10
|
||||
reports fix-or-isolate compliance per cycle.
|
||||
|
||||
**Collect inputs** — every flaky test to register this iteration:
|
||||
|
||||
1. Every flaky test surfaced in Phase 2.1 (intermittent pass/fail across
|
||||
reruns) that was NOT fixed by the Developer this iteration.
|
||||
2. Any flaky test carried over from a prior iteration's report that is still
|
||||
intermittently failing.
|
||||
|
||||
**Step 1 — De-duplicate by failure SIGNATURE against existing families (open
|
||||
AND closed), per `core/rules/testing.md`** (de-duplicate BEFORE filing,
|
||||
retro [TT-2696]). Query `flaky-test` issues in ALL states:
|
||||
|
||||
```
|
||||
GET <gitea-base-url>/api/v1/repos/Octopus/octopus/issues?labels=flaky-test&state=all&page=N&limit=50
|
||||
```
|
||||
|
||||
Match each candidate by **failure signature** — the flakiness mode (timeout /
|
||||
race / order-dependence / env-leak) plus the affected surface, not just
|
||||
`file::test-name` (one root cause may flake several tests). On a signature
|
||||
hit, do NOT create a new ticket: attach the new run evidence (run count,
|
||||
failure rate, commit, sibling tests) as a comment on the FAMILY umbrella
|
||||
ticket. Filing a second ticket inside a known root-cause family is the
|
||||
anti-pattern this phase exists to prevent. If a tracked family now passes
|
||||
deterministically, close its umbrella citing the fixing commit. If the query
|
||||
itself errors (API failure — not "no matches"), retry once; on the second
|
||||
failure proceed to file with the literal marker `dedup-unverified` in the
|
||||
umbrella's first evidence comment (query-failure ruling, [TT-3383] — fail-open,
|
||||
visible; rationale in `core/rules/ticket-lifecycle.md`).
|
||||
|
||||
**Step 2 — Assign the next `FT-NNN`** per `core/rules/testing.md`
|
||||
§ "Flaky tests must be filed, not silently tolerated" (the L1 rule owns the
|
||||
repo-wide sequential numbering invariant — `max + 1`, duplicate ids forbidden
|
||||
incl. closed tickets). `FT-NNN` names the FAMILY.
|
||||
|
||||
**Step 3 — Create one umbrella ticket per NEW root-cause family.** Only when
|
||||
no existing family matches the signature:
|
||||
|
||||
```
|
||||
POST <gitea-base-url>/api/v1/repos/Octopus/octopus/issues
|
||||
body: {"title":"[{origin}] Flaky test: {test identifier} (FT-{NNN})",
|
||||
"body":<issue body template below>,
|
||||
"labels":[flaky_test_label_id, severity_label_id, kind_testing_label_id]}
|
||||
```
|
||||
|
||||
- **Title**: `[{origin}] Flaky test: {signature summary} (FT-{NNN})` — the
|
||||
family's flakiness mode + surface (sibling tests join later as evidence
|
||||
comments, not new tickets).
|
||||
- **Severity** → a flaky test defaults to MEDIUM (HIGH if on a critical path
|
||||
or blocking CI); reuse the exclusive Priority set.
|
||||
- Also attach `Kind/Testing` so it is discoverable in the testing tracker.
|
||||
- **Issue body template**:
|
||||
|
||||
````markdown
|
||||
## Parent / 父级
|
||||
|
||||
{#source_issue, or "no source issue — discovered during iteration verification"}
|
||||
|
||||
## Summary
|
||||
|
||||
A test passes and fails intermittently across runs. It undermines the
|
||||
reliability of the suite and must be stabilized or quarantined.
|
||||
|
||||
| Field | Value |
|
||||
| ------------ | ------------------------- |
|
||||
| FT ID | FT-{NNN} (family) |
|
||||
| Signature | {flakiness mode + surface} |
|
||||
| Tests affected | `{file::test-name}`, … (initial members) |
|
||||
| Origin | {chunk-id/iter-N or slug} |
|
||||
| Severity | {HIGH \| MEDIUM \| LOW} |
|
||||
| Failure rate | {e.g. 3/10 runs} |
|
||||
|
||||
## Reproduction
|
||||
|
||||
```
|
||||
for i in $(seq 1 10); do (cd <harness-package> && bun test --timeout 120000 {test file}) || echo "run $i FAILED"; done
|
||||
```
|
||||
|
||||
## Acceptance Criteria (how to close this issue)
|
||||
|
||||
- [ ] The test passes deterministically across 10 consecutive runs.
|
||||
- [ ] If it cannot be stabilized, it is quarantined (`test.skip` /
|
||||
`test.todo` with a comment citing FT-{NNN}) and a stable replacement
|
||||
is filed as tech-debt (TD-NNN).
|
||||
|
||||
## Context
|
||||
|
||||
- Verification report: `{slug}/05-verify-iteration-{N}`
|
||||
````
|
||||
|
||||
**Step 4 — Cross-link to the source issue (mandatory).** Every flaky-test
|
||||
issue links back to its source via `## Parent`, and the source/parent issue
|
||||
task list references each by `#NNNN`
|
||||
(`- [ ] #NNNN — FT-{NNN} {test identifier}`).
|
||||
|
||||
**Step 5 — Record the mapping in the verification report.** The
|
||||
`FT-NNN → #NNNN` mapping is written ONLY in the Phase 5 report's "Flaky Tests"
|
||||
section (and the issue title). No local file.
|
||||
|
||||
If no unfixed flaky tests exist this iteration, the phase is a no-op — record
|
||||
"0 flaky tests" in the report and proceed.
|
||||
|
||||
<!-- section:phase-5.6 -->
|
||||
### Phase 5.6 — Issue Checklist Sync (final sweep, mandatory before PASS)
|
||||
|
||||
This is the **final** checklist sync — the last of the progressive sync
|
||||
points (requirements exit, design exit, plan exit, each iteration commit, PR
|
||||
creation, review convergence, CI transitions, and here — per the sync-point
|
||||
table in `core/rules/issue-checklist-sync.md`). Earlier syncs may have
|
||||
already checked off completed items; this phase catches everything remaining
|
||||
and ensures no `- [ ]` item is left without an annotation.
|
||||
|
||||
1. **Identify the source issue** per `core/rules/issue-checklist-sync.md`
|
||||
§ "How to sync (each point)" step 1 (find `Closes #N` / `Fixes #N` in the
|
||||
PR body or commit messages). If no source issue exists (e.g. standalone
|
||||
bugfix with no tracking issue), skip this phase.
|
||||
2. **Fetch the issue body** via `工单 API(见 TERMINOLOGY)get` (rule step 2).
|
||||
3. **Map every remaining `- [ ]` checklist item** to one of three states:
|
||||
- **Done** (missed by earlier syncs) → mark `- [x]` and append
|
||||
`_(PR #NNN: <file/component>)_`.
|
||||
- **Deferred** → keep `- [ ]` and append `_(Deferred: TD-NNN <reason>)_`.
|
||||
- **Pending** → keep `- [ ]` and append `_(Pending: <blocker>)_`.
|
||||
4. **Fold the `## 当前状态` live-status section** (if present). Rows that have
|
||||
a checklist counterpart (review, process-ACs) are already reflected as
|
||||
checklist annotations at their sync points. Rows with no checklist
|
||||
counterpart in a non-Epic issue (PR opened/merged) are folded as follow-up
|
||||
evidence on the issue narrative (e.g. `_(PR #NNN merged: <summary>)_` on the
|
||||
item it delivered, or in the report). Once every row is accounted for,
|
||||
remove the section from the issue body.
|
||||
5. **archive-at-close: mark the `## 工件索引` comment archived** (归档动作 — [TT-1929]). Issue
|
||||
closing IS the archive-at-close action; it is explicit, not implicit. Edit the index
|
||||
comment in place per `_shared/gitea-write-patterns.md` Pattern 10 Archive-at-close
|
||||
(mechanism — banner + every row's 重读 → ARCHIVE + invariants — is defined there,
|
||||
do not restate; sequence/actor per `rules/issue-checklist-sync.md` § 归档动作).
|
||||
- Skip if no source issue exists.
|
||||
- **Tier 1 run archive** ([TT-1988] two-tier artifacts — only if a Tier 1 run
|
||||
workspace exists): if `<runs-root>/{slug}/` exists (a stage in this run
|
||||
produced Tier 1 local artifacts, e.g. review-code findings), archive the
|
||||
run workspace per `core/rules/two-tier-artifacts.md` § Archive-at-close
|
||||
(the L1 rule is authoritative — do NOT restate its steps here).
|
||||
The archived bundle must pass
|
||||
`core/schemas/runs-bundle.schema.json` validation (the generator
|
||||
validates by default; a red exit blocks close).
|
||||
Verify deltas only: skip in milestone/task DAG mode (the aggregator agent
|
||||
performs it at Epic/task-ticket close — see the DAG branch below).
|
||||
6. **Update the issue body** via `工单 API(见 TERMINOLOGY)update` with the annotated
|
||||
checklist. Preserve all non-checklist content unchanged.
|
||||
7. **Verify**: re-read the issue and confirm no `- [ ]` item lacks an
|
||||
annotation. Every unchecked item MUST have a `(Deferred: ...)` or
|
||||
`(Pending: ...)` note explaining why it is not done.
|
||||
8. **Close the issue** (completes the archive-at-close loop): if the flow has
|
||||
no PR (no `Closes #N` on merge), the Verifier closes the issue after PASS
|
||||
approval via `工单 API(见 TERMINOLOGY)update(state="closed")` — the banner date is
|
||||
corrected to the actual close date if it differs from today. If a PR carries
|
||||
`Closes #N`, the merge closes it; no further action.
|
||||
|
||||
If a checklist item cannot be mapped to evidence, deferral, or pending
|
||||
status, the iteration is NOT Done — the item represents untracked scope.
|
||||
@@ -2,7 +2,7 @@
|
||||
name: writing-skills
|
||||
description: Use ONLY when creating, editing, or evaluating an octopus skill — writing the SKILL.md body, deciding whether a skill needs baseline testing, or running a blind A/B eval of a behavior-shaping technique. Use BEFORE first deployment of any skill that must hold a process gate under pressure.
|
||||
triggers:
|
||||
# High-discrimination phrases only ([org-internal #4525]). We deliberately do NOT use:
|
||||
# High-discrimination phrases only ([TT-4525]). We deliberately do NOT use:
|
||||
# - bare "skill" / 技能 — collides with every skill discussion. Worse: the
|
||||
# hard skill gate folds the previous assistant turn into its match text on
|
||||
# approval turns, so any model reply containing 技能 (e.g. a gate
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
| 项 | 内容 |
|
||||
|---|---|
|
||||
| slug / 源 DAG 父级 | `{epic-slug}` / #N(`## 父级 / Parent`;DAG 父级 = `Kind/Epic` 或 `Kind/Feature`,[org-internal #3061] 阶段 2——文中「Epic scope」泛指源工单 scope) |
|
||||
| slug / 源 DAG 父级 | `{epic-slug}` / #N(`## 父级 / Parent`;DAG 父级 = `Kind/Epic` 或 `Kind/Feature`,[TT-3061] 阶段 2——文中「Epic scope」泛指源工单 scope) |
|
||||
| 单门 | `review-dag`(TOPO / REQMAP / RELEASE 三维,深度由 `dag_metrics` 导出) |
|
||||
| 评审深度 | `D1 | D2 | D3 | D4`(`dag_metrics.review_depth`) |
|
||||
|
||||
@@ -24,13 +24,13 @@
|
||||
> 仅登记功能性需求(Epic scope 项中的功能性条目)。产品 NFR 不占 `REQ-F` 编号、
|
||||
> 不登记入表、以 `NFR:` 前缀条目落节点 AC(见 §3 `acceptance_criteria`)。
|
||||
> 登记表登记的是「提出者写了什么」;§2.1 类目覆盖矩阵补上「还有什么该问的」
|
||||
> ([org-internal #2905]:legacy elicitation 广度扫描被折叠后的补偿层——`表 ↔ 现实` 完备性)。
|
||||
> ([TT-2905]:legacy elicitation 广度扫描被折叠后的补偿层——`表 ↔ 现实` 完备性)。
|
||||
|
||||
| id | title | source | refs_by |
|
||||
|---|---|---|---|
|
||||
| REQ-F-001 | {需求标题} | {Epic scope 项} | {引用节点 id 集} |
|
||||
|
||||
### 2.1 类目覆盖矩阵([org-internal #2905] 方案 1)
|
||||
### 2.1 类目覆盖矩阵([TT-2905] 方案 1)
|
||||
|
||||
> 固定类目集(≤10 类,自 legacy `.octopus/archive/checklists/requirements-analysis.md` CMP/SAF 维抽取)。
|
||||
> 每类目状态 ∈ {已覆盖, 明确排除, 待确认}:
|
||||
@@ -55,7 +55,7 @@
|
||||
| 错误与边界场景(CMP 1.11:空输入/边界值/异常状态,Epic 级;节点级路径覆盖由 REQMAP「AC 路径覆盖」承担) | {已覆盖/明确排除/待确认} | {证据/指针} |
|
||||
| 假设与依赖(CMP 1.9:列出并评估影响) | {已覆盖/明确排除/待确认} | {证据/指针} |
|
||||
|
||||
### 2.2 排除账本([org-internal #2905] 方案 1)
|
||||
### 2.2 排除账本([TT-2905] 方案 1)
|
||||
|
||||
> 「明确排除」的唯一凭证登记处。每行一条 `E-n`:条目 — out of scope、理由、确认人。
|
||||
> 排除可逆:重开时删行并把 §2.1 矩阵状态改为「已覆盖/待确认」,同一次修订内完成。
|
||||
|
||||
@@ -5,17 +5,17 @@ Normative layout for **Tier 1 local structured artifacts**. Authoritative
|
||||
boundary rule: `core/rules/two-tier-artifacts.md`. Schemas that validate
|
||||
the structured files below live in `core/schemas/runs-*.schema.json`.
|
||||
|
||||
This document is the **foundation** (MVP slice, [org-internal #1968]). It defines the
|
||||
This document is the **foundation** (MVP slice, [TT-1968]). It defines the
|
||||
container, the manifest, and the metadata. Stage-specific artifact schemas
|
||||
(design detail dumps, plan items, review dimension findings, synthesis
|
||||
prompts, draft contracts) are added incrementally as each skill migrates its
|
||||
transient output here — the follow-up iteration ([org-internal #1988]) has landed: `review-artifact` /
|
||||
transient output here — the follow-up iteration ([TT-1988]) has landed: `review-artifact` /
|
||||
`audit-process` raw findings and producer working drafts are now Tier 1.
|
||||
([org-internal #3072] phase 3, 2026-08-21: the legacy producer stages whose drafts are listed
|
||||
([TT-3072] phase 3, 2026-08-21: the legacy producer stages whose drafts are listed
|
||||
below were archived — their rows and artifact dirs are kept for reading
|
||||
historical run bundles.) See the migrated stages table below.
|
||||
|
||||
## Kind/MVP mode ([org-internal #3061])
|
||||
## Kind/MVP mode ([TT-3061])
|
||||
|
||||
`Kind/MVP` tickets write **nothing** to `<runs-root>/` by design — no stage
|
||||
dirs, no `index.json`, no manifest. The ticket body is the doc (`## 决策日志`
|
||||
@@ -47,8 +47,8 @@ for human-visible decisions.
|
||||
└── {active-slug}/ # GITIGNORED — one subdir per active run
|
||||
├── meta.json # run metadata (runs-meta.schema.json)
|
||||
├── index.json # artifact manifest (runs-index.schema.json)
|
||||
├── working-notes.md # cross-stage narrative memory ([org-internal #2600], schema-less md)
|
||||
├── workers/ # worker final-return reports ([org-internal #2847], schema-less md —
|
||||
├── working-notes.md # cross-stage narrative memory ([TT-2600], schema-less md)
|
||||
├── workers/ # worker final-return reports ([TT-2847], schema-less md —
|
||||
│ └── ... # see _shared/worker-report-persistence.md)
|
||||
└── {stage}/ # per-stage transient artifacts (added by skills)
|
||||
└── ... # json (structured) / md (prompt files)
|
||||
@@ -61,7 +61,7 @@ for human-visible decisions.
|
||||
- **Gitignored** while active — subagents share the worktree, not the git
|
||||
history, so active-run content stays local (no repo bloat, no merge noise).
|
||||
- **Initialized at run start** by `bun <harness-package>/script/runs-init.ts
|
||||
--slug {slug} --ticket N [--branch …] [--worktree …]` ([org-internal #3642]) — the
|
||||
--slug {slug} --ticket N [--branch …] [--worktree …]` ([TT-3642]) — the
|
||||
producing role / Orchestrator runs the script (hand-writing the files is the
|
||||
legacy path): it creates the `{active-slug}/` workspace, writes `meta.json`
|
||||
with `state: "active"` and the run's slug/branch/worktree/ticket (branch
|
||||
@@ -118,7 +118,7 @@ issue comment: the former is the agent's compact-recovery entry; the latter is
|
||||
the human-visible traceability hub. They are kept in sync by the producing
|
||||
role but serve different consumers.
|
||||
|
||||
### `working-notes.md` — cross-stage narrative memory ([org-internal #2600])
|
||||
### `working-notes.md` — cross-stage narrative memory ([TT-2600])
|
||||
|
||||
`index.json` is a MANIFEST: it records WHAT artifacts exist. It does not
|
||||
carry WHY code was written that way, which paths were tried and abandoned, or
|
||||
@@ -148,7 +148,7 @@ is that narrative memory, in-file, append-only:
|
||||
decision ✓, never referenced cross-worktree ✓, archivable at close ✓ — all
|
||||
four Tier 1 conditions hold (`core/rules/two-tier-artifacts.md` 判据).
|
||||
|
||||
### `workers/` — worker final-return reports ([org-internal #2847])
|
||||
### `workers/` — worker final-return reports ([TT-2847])
|
||||
|
||||
Every worker sub-agent dispatch (`agent: worker` roles — Producer
|
||||
sub-roles, Verifier, Synthesizer) persists its **final return report**
|
||||
@@ -164,7 +164,7 @@ generic name. `index.json` row: `type: "other"`, `schema: null`, `stage` =
|
||||
producing stage, `produced_by` = role. Full convention:
|
||||
`core/skills/_shared/worker-report-persistence.md`.
|
||||
|
||||
### `browser/` — browser evidence packs ([org-internal #4497] N-03)
|
||||
### `browser/` — browser evidence packs ([TT-4497] N-03)
|
||||
|
||||
A browser-debug session writes one evidence pack per session under
|
||||
`browser/{session-id}/` (contract `browser-evidence-4486/shared/pack-manifest-v1`,
|
||||
@@ -204,20 +204,20 @@ Conventions established by this foundation:
|
||||
- A stage that has not yet migrated continues to write to Gitea (Tier 2) per its
|
||||
existing skill body — the two tiers coexist during the migration.
|
||||
|
||||
**Migrated stages ([org-internal #1988]):**
|
||||
**Migrated stages ([TT-1988]):**
|
||||
|
||||
| Stage | Skill | Tier 1 artifacts | Schema | Notes |
|
||||
|---|---|---|---|---|
|
||||
| `review-code` | review-code | `reviews/code/round{N}/findings-{DIM}.json` (raw dimension findings), `reviews/code/round{N}/task-synthesizer.md` (synthesis prompt) | `reviewer-output.schema.json` (findings) | synthesis comment + commit status stay Tier 2 |
|
||||
| `review-roadmap` | review | `reviews/roadmap/round{N}/findings-{DIM}.json` | `reviewer-output.schema.json` | legacy target archived ([org-internal #3072] phase 3) — row kept for historical bundles |
|
||||
| `review-design-space` | review | `reviews/design-space/round{N}/findings-{DIM}.json` | `reviewer-output.schema.json` | legacy target archived ([org-internal #3072] phase 3) — row kept for historical bundles |
|
||||
| `review-iteration-plan` | review | `reviews/plan/round{N}/findings-{DIM}.json` | `reviewer-output.schema.json` | legacy target archived ([org-internal #3072] phase 3) — row kept for historical bundles |
|
||||
| `review-roadmap` | review | `reviews/roadmap/round{N}/findings-{DIM}.json` | `reviewer-output.schema.json` | legacy target archived ([TT-3072] phase 3) — row kept for historical bundles |
|
||||
| `review-design-space` | review | `reviews/design-space/round{N}/findings-{DIM}.json` | `reviewer-output.schema.json` | legacy target archived ([TT-3072] phase 3) — row kept for historical bundles |
|
||||
| `review-iteration-plan` | review | `reviews/plan/round{N}/findings-{DIM}.json` | `reviewer-output.schema.json` | legacy target archived ([TT-3072] phase 3) — row kept for historical bundles |
|
||||
| `review-dag` | review | `reviews/review-dag/round{N}/findings-{DIM}.json` | `reviewer-output.schema.json` | synthesis comment + commit status stay Tier 2 |
|
||||
| `audit-process` | review | `reviews/audit-process/round{N}/findings-{DIM}.json` | `reviewer-output.schema.json` | synthesis wiki page + commit status stay Tier 2 |
|
||||
| `requirements` (drafts) | requirements-elicitation | `requirements/` (schema-less `.md`/`.json`) | — | legacy skill archived ([org-internal #3072] phase 3) — historical bundles only |
|
||||
| `design` (drafts) | design | `design/` (schema-less or `design-detail.schema.json`) | `design-detail.schema.json` (moved to `<instance-root>/archive/schemas/` [org-internal #3072] phase 3) | legacy skill archived ([org-internal #3072] phase 3) — historical bundles only |
|
||||
| `plan-iterations` (drafts) | plan-iterations | `plan-iterations/` (schema-less or `plan-items.schema.json`) | `plan-items.schema.json` (moved to `<instance-root>/archive/schemas/` [org-internal #3072] phase 3) | legacy skill archived ([org-internal #3072] phase 3) — historical bundles only |
|
||||
| `roadmap` (draft contracts) | roadmap | `roadmap/contracts/{name}.json` | `draft-contract.schema.json` (moved to `<instance-root>/archive/schemas/` [org-internal #3072] phase 3) | legacy skill archived ([org-internal #3072] phase 3) — historical bundles only |
|
||||
| `requirements` (drafts) | requirements-elicitation | `requirements/` (schema-less `.md`/`.json`) | — | legacy skill archived ([TT-3072] phase 3) — historical bundles only |
|
||||
| `design` (drafts) | design | `design/` (schema-less or `design-detail.schema.json`) | `design-detail.schema.json` (moved to `<instance-root>/archive/schemas/` [TT-3072] phase 3) | legacy skill archived ([TT-3072] phase 3) — historical bundles only |
|
||||
| `plan-iterations` (drafts) | plan-iterations | `plan-iterations/` (schema-less or `plan-items.schema.json`) | `plan-items.schema.json` (moved to `<instance-root>/archive/schemas/` [TT-3072] phase 3) | legacy skill archived ([TT-3072] phase 3) — historical bundles only |
|
||||
| `roadmap` (draft contracts) | roadmap | `roadmap/contracts/{name}.json` | `draft-contract.schema.json` (moved to `<instance-root>/archive/schemas/` [TT-3072] phase 3) | legacy skill archived ([TT-3072] phase 3) — historical bundles only |
|
||||
|
||||
Every review/audit stage additionally maintains a per-stage lifecycle file
|
||||
`reviews/{stage}/status.json` (schema `review-status.schema.json`) — live
|
||||
@@ -241,24 +241,24 @@ enters git history:
|
||||
2. Write `archive/{slug}.json` — a compact bundle carrying `meta` + the
|
||||
`index.json` manifest (the durable trace; bulk artifacts are summarized by
|
||||
digest, not copied wholesale, to keep the archive small). One exception
|
||||
([org-internal #2600]): when `working-notes.md` exists, its final content is inlined as
|
||||
([TT-2600]): when `working-notes.md` exists, its final content is inlined as
|
||||
the bundle's top-level `working_notes` field — the narrative memory is the
|
||||
single artifact whose content (not just digest) rides in the bundle,
|
||||
feeding later retro probes and the notes-injection degradation path
|
||||
([org-internal #2601]). The bundle is validated by `runs-bundle.schema.json`.
|
||||
Offline review verifiability (TD/TRC-F006, [org-internal #2688]): for each review stage
|
||||
([TT-2601]). The bundle is validated by `runs-bundle.schema.json`.
|
||||
Offline review verifiability (TD/TRC-F006, [TT-2688]): for each review stage
|
||||
the run executed, also embed a top-level `review_history` entry in the
|
||||
bundle — `{stage, rounds, final_verdict, per_round[]}` (per-round:
|
||||
round/overall_verdict/blockers/majors/minors) — derived from that stage's
|
||||
live `reviews/{stage}/status.json` `history[]`. Closed-run probes can then
|
||||
reconstruct round counts and verdicts from the bundle alone, without the
|
||||
removed workspace or artifact-path reconstruction ([org-internal #2591]).
|
||||
removed workspace or artifact-path reconstruction ([TT-2591]).
|
||||
3. `git add archive/{slug}.json` and commit on the workflow branch (rides into
|
||||
main via the `--no-ff` merge).
|
||||
4. Remove the `{active-slug}/` workspace from the worktree (its durable record
|
||||
now lives in the archive bundle).
|
||||
|
||||
Steps 1–4 collapse into ONE command ([org-internal #3642]): `bash script/archive-run.sh
|
||||
Steps 1–4 collapse into ONE command ([TT-3642]): `bash script/archive-run.sh
|
||||
{slug} [--pr N]` — run from the session worktree, it resolves the PR by branch
|
||||
head, generates + validates the bundle via `gen-run-bundle.ts` (recording
|
||||
`closed_at` / `close_commit_sha` and the `--branch` workflow branch), commits
|
||||
@@ -274,7 +274,7 @@ Gitea tax.
|
||||
|
||||
## Relationship to existing mechanisms
|
||||
|
||||
- **`/tmp/octopus/` embryo** — `review-code` ([org-internal #1988] MVP) now writes its
|
||||
- **`/tmp/octopus/` embryo** — `review-code` ([TT-1988] MVP) now writes its
|
||||
synthesis prompt under `<runs-root>/{slug}/reviews/code/` instead of
|
||||
`/tmp/octopus/synthesis_task_*`. Other skills still using the `/tmp/octopus/`
|
||||
embryo coexist until their own migration iteration.
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
import fs from "node:fs"
|
||||
import path from "node:path"
|
||||
|
||||
const ROOT = path.resolve(import.meta.dir, "..")
|
||||
const scriptDir = (import.meta as { dir?: string }).dir
|
||||
?? new URL(".", import.meta.url).pathname
|
||||
const ROOT = path.resolve(scriptDir, "..")
|
||||
const MANIFEST_PATH = path.join(ROOT, "core", "CORE-MANIFEST.json")
|
||||
const CORE_ROOT = path.join(ROOT, "core")
|
||||
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
import fs from "node:fs"
|
||||
import path from "node:path"
|
||||
|
||||
const ROOT = path.resolve(import.meta.dir, "..")
|
||||
const scriptDir = (import.meta as { dir?: string }).dir
|
||||
?? new URL(".", import.meta.url).pathname
|
||||
const ROOT = path.resolve(scriptDir, "..")
|
||||
const CORE_ROOT = path.join(ROOT, "core")
|
||||
const EXEMPT = new Set(["core/schemas/id-aliases.json"])
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
import fs from "node:fs"
|
||||
import path from "node:path"
|
||||
|
||||
const scriptDir = (import.meta as { dir?: string }).dir
|
||||
?? new URL(".", import.meta.url).pathname
|
||||
const ROOT = path.resolve(scriptDir, "..")
|
||||
const CORE_DIR = path.join(ROOT, "core")
|
||||
|
||||
const SCAN_EXTENSIONS = new Set([".md", ".json", ".ts", ".tsx", ".js", ".mjs", ".cjs", ".yaml", ".yml", ".txt"])
|
||||
|
||||
export const MOJIBAKE_SIGNATURES: { name: string; pattern: RegExp }[] = [
|
||||
{ name: "em-dash-mojibake", pattern: /\u9225/ },
|
||||
{ name: "right-arrow-mojibake", pattern: /\u922B/ },
|
||||
{ name: "check-mark-mojibake", pattern: /\u9257|\u9253/ },
|
||||
{ name: "cross-mark-mojibake", pattern: /\u9242/ },
|
||||
{ name: "geq-mojibake", pattern: /\u922E/ },
|
||||
{ name: "multiplication-mojibake", pattern: /\u8137/ },
|
||||
{ name: "replacement-char", pattern: /\uFFFD/ },
|
||||
{ name: "truncated-mojibake", pattern: /[\u9000-\u9FFF]\?/ },
|
||||
{ name: "gbk-cjk-bigram", pattern: /椤圭|鍒濆|閰嶇|鐨勶|鎷夎|浼氳瘽|鏃犲|淇濇|缁戝|瀹屾|涓珛|鏀瑰啓|瀹炰緥|鎵归|寤惰|璋冨|绀轰|鍘熸|閰嶉|鎹薄|閫昏|椤甸|绔犵|宸插|鍒嗛|鍏抽|鍚岀|鍚庣|鍓嶇|杩斿|杩涘|閫変|鎸夌|鏉冮|鏂囦|鏂囨/ },
|
||||
]
|
||||
|
||||
export interface EncodingViolation {
|
||||
file: string
|
||||
line: number
|
||||
signature: string
|
||||
match: string
|
||||
}
|
||||
|
||||
export function scanFile(filePath: string): EncodingViolation[] {
|
||||
const text = fs.readFileSync(filePath, "utf8")
|
||||
const violations: EncodingViolation[] = []
|
||||
const lines = text.split(/\r?\n/)
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
for (const sig of MOJIBAKE_SIGNATURES) {
|
||||
const m = lines[i]!.match(sig.pattern)
|
||||
if (m) {
|
||||
violations.push({
|
||||
file: filePath,
|
||||
line: i + 1,
|
||||
signature: sig.name,
|
||||
match: m[0]!,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return violations
|
||||
}
|
||||
|
||||
export function collectFiles(dir: string): string[] {
|
||||
const out: string[] = []
|
||||
if (!fs.existsSync(dir)) return out
|
||||
const walk = (d: string) => {
|
||||
for (const entry of fs.readdirSync(d, { withFileTypes: true })) {
|
||||
const full = path.join(d, entry.name)
|
||||
if (entry.isDirectory()) walk(full)
|
||||
else if (SCAN_EXTENSIONS.has(path.extname(entry.name))) out.push(full)
|
||||
}
|
||||
}
|
||||
walk(dir)
|
||||
return out.sort()
|
||||
}
|
||||
|
||||
function main(): void {
|
||||
if (!fs.existsSync(CORE_DIR)) {
|
||||
console.error(`check-encoding-health: core/ directory not found at ${CORE_DIR} — cannot verify (fail-closed)`)
|
||||
process.exit(1)
|
||||
}
|
||||
const files = collectFiles(CORE_DIR)
|
||||
if (files.length === 0) {
|
||||
console.error(`check-encoding-health: 0 scannable files under ${CORE_DIR} — cannot verify (fail-closed)`)
|
||||
process.exit(1)
|
||||
}
|
||||
const violations: EncodingViolation[] = []
|
||||
for (const f of files) {
|
||||
try {
|
||||
violations.push(...scanFile(f))
|
||||
} catch (err) {
|
||||
console.error(`check-encoding-health: failed to read ${f}: ${(err as Error).message}`)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
if (violations.length > 0) {
|
||||
console.error(`check-encoding-health: ${violations.length} mojibake violation(s) in core/:`)
|
||||
for (const v of violations) {
|
||||
const rel = path.relative(ROOT, v.file)
|
||||
console.error(` ${rel}:${v.line} [${v.signature}] ${JSON.stringify(v.match)}`)
|
||||
}
|
||||
process.exit(1)
|
||||
}
|
||||
console.log(`check-encoding-health: OK (${files.length} files scanned, 0 violations)`)
|
||||
}
|
||||
|
||||
if (import.meta.main) main()
|
||||
+23
-3
@@ -3,12 +3,20 @@
|
||||
import fs from "node:fs"
|
||||
import path from "node:path"
|
||||
|
||||
const ROOT = path.resolve(import.meta.dir, "..")
|
||||
// Runtime-neutral: works under bun and node>=20.9 (--experimental-strip-types).
|
||||
const scriptDir = (import.meta as { dir?: string }).dir
|
||||
?? new URL(".", import.meta.url).pathname
|
||||
const ROOT = path.resolve(scriptDir, "..")
|
||||
const MANIFEST_PATH = path.join(ROOT, "core", "CORE-MANIFEST.json")
|
||||
const CHECK = process.argv.includes("--check")
|
||||
// --strip: rewrite remaining `[org-internal #NNNN]` annotations to a compact
|
||||
// provenance form `[TT-NNNN]` (org ticket id, non-navigable in the standalone
|
||||
// repo) and fold the wordy placeholder away. Idempotent like the base pass.
|
||||
const STRIP = process.argv.includes("--strip")
|
||||
|
||||
const REF_RE = /\B#(\d{3,5})\b/g
|
||||
const PLACEHOLDER = "org-internal"
|
||||
const STRIP_RE = /\[org-internal[ \t]*#(\d{3,5})\]/g
|
||||
|
||||
interface Mapping {
|
||||
core: string
|
||||
@@ -61,6 +69,16 @@ function transformContent(content: string): { next: string; count: number } {
|
||||
return { next, count }
|
||||
}
|
||||
|
||||
// --strip pass: `[org-internal #NNNN]` → `[TT-NNNN]` (provenance-only ticket id).
|
||||
function stripContent(content: string): { next: string; count: number } {
|
||||
let count = 0
|
||||
const next = content.replace(STRIP_RE, (_match, digits: string) => {
|
||||
count++
|
||||
return `[TT-${digits}]`
|
||||
})
|
||||
return { next, count }
|
||||
}
|
||||
|
||||
export function transformContentForTest(content: string): { next: string; count: number } {
|
||||
return transformContent(content)
|
||||
}
|
||||
@@ -73,7 +91,8 @@ let replacedTotal = 0
|
||||
for (const rel of files) {
|
||||
const fullRel = `core/${rel}`
|
||||
const content = fs.readFileSync(path.join(ROOT, "core", rel), "utf8")
|
||||
const { next, count } = transformContent(content)
|
||||
const result = STRIP ? stripContent(content) : transformContent(content)
|
||||
const { next, count } = result
|
||||
if (count === 0) continue
|
||||
if (byteLocked.has(fullRel)) {
|
||||
deferredLocked.push({ file: fullRel, count })
|
||||
@@ -101,7 +120,8 @@ if (CHECK) {
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
console.log(`delink-core: replaced ${replacedTotal} refs across ${perFile.length} file(s)`)
|
||||
const mode = STRIP ? "stripped" : "replaced"
|
||||
console.log(`delink-core: ${mode} ${replacedTotal} refs across ${perFile.length} file(s)`)
|
||||
const top = [...perFile, ...deferredLocked].sort((a, b) => b.count - a.count).slice(0, 10)
|
||||
for (const p of top) console.log(` ${p.file}: ${p.count}`)
|
||||
process.exit(0)
|
||||
|
||||
+3
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "octopus-workflow",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.4",
|
||||
"description": "Standalone workflow core: provider-neutral agent workflow corpus (skills / rules / checklists / templates / schemas) with drift guards, extracted from the octopus agent platform.",
|
||||
"license": "MIT",
|
||||
"private": false,
|
||||
@@ -9,7 +9,8 @@
|
||||
"scripts": {
|
||||
"check:core-cohesion": "bun guards/check-core-cohesion.ts",
|
||||
"check:core-p1": "bun guards/check-core-p1.ts",
|
||||
"delink:core": "bun guards/delink-core.ts"
|
||||
"delink:core": "bun guards/delink-core.ts",
|
||||
"check:encoding-health": "bun guards/check-encoding-health.ts"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
# 项目复盘 — wechat-ops 个人微信 GUI 自动化值守 Agent
|
||||
|
||||
> 迭代周期:2026-09-29 一天(迭代0 环境搭建 → 迭代1 五功能 → 迭代2 DAG 就位)
|
||||
> 方法:Loong Workflow 复盘清单(DATA / ANAL / ACT / LOOP / SAFE)
|
||||
> 复盘人:kenyang + ZCode Agent
|
||||
|
||||
---
|
||||
|
||||
## 0. 项目快照
|
||||
|
||||
| 项 | 值 |
|
||||
|---|---|
|
||||
| 交付物 | GitHub + Loong Gitea 双远端 wechat-ops(skILL 包 + 服务器部署版,md5 一致) |
|
||||
| 代码规模 | agent.py ~650 行 + vision.py + setup-server.sh + 守卫脚本 |
|
||||
| 运行状态 | 阿里云 2核2G,auto/draft 值守中,可用内存 ~720Mi |
|
||||
| 版本轨迹 | v0.1.0 初版 → v0.2.x 安全加固 → v0.3.x ima 知识库 → v0.4.x Loong 工作流捆绑 |
|
||||
|
||||
## 1. 数据(DATA)
|
||||
|
||||
**功能交付**:迭代1 五项全部实现并验证(独立Prompt/记忆/群@检测/链接阅读/图标模板匹配);ima OpenAPI 当天逆向对接(官方文档缺字段不一致,实测修正)。
|
||||
|
||||
**真实流量拦截记录**(守卫闸门的实战证据):
|
||||
- 标题核验拦截误发:6+ 次(误定位到 第一财经/大刘家/杨家小极客/张秀英/纯臻群/刘家四兄弟姐妹)
|
||||
- 白名单外跳过:9+ 次(张秀英门店运营群、2组1号、Service Accounts 等)
|
||||
- 群 @ 闸门:未@消息全部仅记录不响应
|
||||
|
||||
**事故清单**(每条有日志/截图证据):
|
||||
1. 私聊消息误发 227 人群(坐标偏移+无核验,用户手动撤回)
|
||||
2. Escape 键打崩微信渲染→透明壳→自愈误判重启→登录会话丢失(被迫重扫码 3 次)
|
||||
3. 定时任务队列被清空且重复触发 20 秒循环(FT 收到 ~50 条测试消息)
|
||||
4. 工单误关 4 张(#6/#7/#8/#9 号映射错误,事后纠正)
|
||||
5. linux-server.md 被存根覆盖丢失 90 行(git 历史恢复)
|
||||
6. ima 官方文档字段与实际 API 不一致(id/name vs kb_id/kb_name)
|
||||
|
||||
## 2. 优点(可复用模式)
|
||||
|
||||
1. **安全闸门代码化且实战有效**:标题核验(空标题拒绝)、白名单、限速、静默、敏感词回退——全部误发被拦,零事故外泄。模式:闸门必须写成函数,不写成散文。
|
||||
2. **自愈状态机**:托盘隐匿/透明壳/登录过期/过渡态保护,一夜之间无人工干预恢复值守。模式:每种故障先做"最坏情况审查"再加处理分支。
|
||||
3. **像素级兜底 + 自学习模板**:FT 图标颜色候选 + 9×9 模板最小距离(校准:真身<10万,误配 270万+),核验成功后自学习存模板。
|
||||
4. **知识库两级接入**:文件导出兜底 + OpenAPI 直连优先,当天完成无官方文档接口的逆向对接(实测修正字段名)。
|
||||
5. **诚实文化**:幻觉试答拒绝发送;错误关票发状态修正评论;证据分级表述(已验证:证据 / 未验证:待确认)。
|
||||
6. **真实用户即时反馈**:群里演示后,当晚有成员尝试部署、有成员购入服务器——开源定位(纯视觉替代付费 Proxy API)得到验证。
|
||||
|
||||
## 3. 缺点与根因(归因流程/工具,不归因个人)
|
||||
|
||||
| # | 缺点 | 根因(流程/工具缺口) |
|
||||
|---|---|---|
|
||||
| 1 | GUI 自动化固有脆弱:窗口自发隐匿、渲染透明壳、Escape 打崩渲染,全天 5+ 次异常 | 微信 Qt 客户端不可控;缺"故障注入"式预防测试,只有事后补丁 |
|
||||
| 2 | 免费视觉模型定位误读(臻→甄、槽位名字偏差),需模板/模糊匹配补丁补偿 | 无离线评测集:视觉提示词从未做过基线测试,每个误读都是第一次见 |
|
||||
| 3 | 定时任务重复触发 20 秒循环,根因未明(run_due_tasks 曾将未到期任务判为 due) | 缺"决策日志→断言"的最小复现方法论;护栏先于根因分析上线,护栏自身又制造新循环 |
|
||||
| 4 | 群发误投事故 | 无"发送目标 dry-run"预检步骤;核验闸门是事故后补的 |
|
||||
| 5 | 工单误关 4 张(映射错误) | 关票动作无"工单号↔标题"双重校验;单人无评审 |
|
||||
| 6 | 文档被存根覆盖 90 行 | 文件同步用 cp 而非 git,缺 pre-commit 保护 |
|
||||
| 7 | 测试污染真实会话(FT ~50 条消息) | 无测试专用会话/账号隔离机制 |
|
||||
|
||||
## 4. 行动项(ACT,≤5,每条有文件路径与完成判据)
|
||||
|
||||
| # | 行动项 | 文件 | 完成判据 |
|
||||
|---|---|---|---|
|
||||
| 1 | N-04:定时任务重复触发复现(利用 save_tasks([]) 溯源栈日志) | scripts/agent.py run_due_tasks | 同一任务 3 次评估仅触发 1 次发送 |
|
||||
| 2 | N-05:白名单 difflib≥0.6 模糊匹配(已实现待回归) + 群名 OCR 变体测试用例集 | scripts/agent.py handle_trigger | 「纯甄AI赋能1688」命中白名单 |
|
||||
| 3 | N-01:图片发送链路(表情包前置) | scripts/agent.py send_image | 测试图片送达 File Transfer |
|
||||
| 4 | 上架前置:守卫脚本增加"凭证/隐私 HARD 扫描"进 CI(双远端推送前自动跑) | scripts/check-skill.sh + Loong Gitea workflow | push 即自动扫描 |
|
||||
| 5 | ima 检索评测集:收集 10 条真实问题-期望文档对,做召回率基线 | references/ima-eval.md(新建) | 召回率报告存在且 ≥8/10 |
|
||||
|
||||
## 5. 闭环(LOOP)
|
||||
|
||||
- 本文写入 loong-workflow 仓库 retrospectives/
|
||||
- ACT#1/#2 相关坑已沉淀 pitfalls-linux.md(#18/#19/#20)
|
||||
- 迭代2 DAG 已发布 Loong Gitea wiki(wechat-ops-iter2/dag),N-01 工单已建(#14)
|
||||
|
||||
## 6. 无指责声明(SAFE)
|
||||
|
||||
所有失误(群发误投、误关工单、文档覆盖、护栏制造循环)归因于:**流程缺口**(无 dry-run、无双人评审、无离线测试集、护栏先于根因分析),不归因于任何人的能力或态度。相应修复均已落入上述 ACT 项。
|
||||
|
||||
## 7. 一句话总结
|
||||
|
||||
**一天内从裸机到开源值守 Agent,安全闸门零失效,但稳定性工程(故障注入测试、离线评测集、双人评审)仍是单人项目的最大短板——这三样是迭代2 的主攻方向。**
|
||||
Reference in New Issue
Block a user