diff --git a/core/README.md b/core/README.md index 229094c..d46e2b4 100644 --- a/core/README.md +++ b/core/README.md @@ -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 三份规则是从实例规则**逐字复制**的,规则正文里出现实例路径字样属 diff --git a/core/adapters/TERMINOLOGY.md b/core/adapters/TERMINOLOGY.md index 710b588..0339350 100644 --- a/core/adapters/TERMINOLOGY.md +++ b/core/adapters/TERMINOLOGY.md @@ -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` | | 会话工作树路径(并发分支工作区根) | `` | | 测试命令·变更集(本地前置检查) | `bun run test:changed` | diff --git a/core/adapters/gitea/patterns.md b/core/adapters/gitea/patterns.md index 8052638..eba2014 100644 --- a/core/adapters/gitea/patterns.md +++ b/core/adapters/gitea/patterns.md @@ -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`(本文不重复)。 > 实例基址由实例配置提供(下文 ``),见 -> `core/adapters/TERMINOLOGY.md`。 +> `core/adapters/TERMINOLOGY.md`。认证一律 `-H "Authorization: token "`; +> 端点契约以 `/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 "/api/v1/repos/Octopus/octopus/wiki/new" \ + -H "Authorization: token " -H "Content-Type: application/json" \ + -d '{ + "title": "{slug}/{type}-{seq:02d}-{title}", + "content_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 " \ + "/api/v1/repos/Octopus/octopus/wiki/pages" +# 2. 用返回的 sub_url 原样读页 +curl -fsS -H "Authorization: token " \ + "/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 "/api/v1/repos/Octopus/octopus/wiki/page/{sub_url}" \ + -H "Authorization: token " -H "Content-Type: application/json" \ + -d '{ + "content_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 "/api/v1/repos/Octopus/octopus/issues" \ + -H "Authorization: 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 "/api/v1/repos/Octopus/octopus/issues/{index}" \ + -H "Authorization: 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 "/api/v1/repos/Octopus/octopus/issues/{index}/comments" \ + -H "Authorization: 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 "/api/v1/repos/Octopus/octopus/issues/comments/{comment_id}" \ + -H "Authorization: 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 " \ + "/api/v1/repos/Octopus/octopus/projects" +# 列某 project 的 columns +curl -fsS -H "Authorization: token " \ + "/api/v1/repos/Octopus/octopus/projects/{project_id}/columns" +# 移动工单到列:先经 swagger.v1.json 查询 projects 相关端点后调用 +curl -s /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 "/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 /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 " \ + "/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} 关闭于 diff --git a/core/adapters/gitea/reading.md b/core/adapters/gitea/reading.md index 9ddd055..c8ea51c 100644 --- a/core/adapters/gitea/reading.md +++ b/core/adapters/gitea/reading.md @@ -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 " \ + "/api/v1/repos/Octopus/octopus/wiki/pages" +# 2. 用返回的 sub_url 原样读页(含 %2F 编码与 .- 尾缀) +curl -fsS -H "Authorization: token " \ + "/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="/{repo}-wiki/") ## Pattern 2: read-issue ``` -gitea_issue__get(owner="Octopus", repo="octopus", index={issue_number}) +curl -fsS -H "Authorization: token " \ + "/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 " \ + "/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 " \ + "/api/v1/repos/Octopus/octopus/projects" +curl -fsS -H "Authorization: token " \ + "/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 " \ + "/api/v1/repos/Octopus/octopus/issues/{issue_number}" +# 2. 拉评论列表,找 body 以 "## 工件索引"(遗留 "## Pipeline 工件追踪表")开头的评论 +curl -fsS -H "Authorization: token " \ + "/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 " \ + "/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 + diff --git a/core/rules/claim-discipline.md b/core/rules/claim-discipline.md index 304f9a8..be85fd5 100644 --- a/core/rules/claim-discipline.md +++ b/core/rules/claim-discipline.md @@ -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 + /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 @@ -52,5 +53,6 @@ plausible-looking result to fill the gap. 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. +full review JSON when the wiki tool surface (MCP tooling at the time, now +retired) was unavailable to subagents. diff --git a/core/skills/_shared/review-pipeline-phases.md b/core/skills/_shared/review-pipeline-phases.md index 2ea423b..165b0b6 100644 --- a/core/skills/_shared/review-pipeline-phases.md +++ b/core/skills/_shared/review-pipeline-phases.md @@ -68,12 +68,13 @@ in `_shared/gitea-write-patterns.md`. 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 /api/v1/repos/{owner}/{repo}/wiki/pages` with + `-H "Authorization: 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 [org-internal #2115]): verify the **local wiki clone** at `/{repo}-wiki/` is readable — `glob(pattern="*.md", path="/{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 `/{repo}-wiki/`). + gap so the environment can be fixed (restore Gitea REST reachability — + token validity, network route — or + populate `/{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: @@ -471,8 +473,10 @@ 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 /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, diff --git a/core/skills/_shared/review-reviewer-prompt.md b/core/skills/_shared/review-reviewer-prompt.md index 106dae3..c984b93 100644 --- a/core/skills/_shared/review-reviewer-prompt.md +++ b/core/skills/_shared/review-reviewer-prompt.md @@ -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 /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 diff --git a/core/skills/headless-session-ops/reference/ticket-recipe.md b/core/skills/headless-session-ops/reference/ticket-recipe.md index 123f86e..f727904 100644 --- a/core/skills/headless-session-ops/reference/ticket-recipe.md +++ b/core/skills/headless-session-ops/reference/ticket-recipe.md @@ -65,8 +65,8 @@ 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 /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 sessions — check the remote too: diff --git a/core/skills/implement/reference/bugfix-mode.md b/core/skills/implement/reference/bugfix-mode.md index dba16fe..71d9569 100644 --- a/core/skills/implement/reference/bugfix-mode.md +++ b/core/skills/implement/reference/bugfix-mode.md @@ -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 ``` diff --git a/core/skills/implement/reference/implement-mode.md b/core/skills/implement/reference/implement-mode.md index 198a1ae..04d8e2f 100644 --- a/core/skills/implement/reference/implement-mode.md +++ b/core/skills/implement/reference/implement-mode.md @@ -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 /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`. diff --git a/core/skills/implement/reference/refactor-mode.md b/core/skills/implement/reference/refactor-mode.md index e0fcac4..c75afa2 100644 --- a/core/skills/implement/reference/refactor-mode.md +++ b/core/skills/implement/reference/refactor-mode.md @@ -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 /api/v1/repos/{owner}/{repo}/wiki/page/{mangled-name}`. Or "None".} --- diff --git a/core/skills/review-artifact/SKILL.md b/core/skills/review-artifact/SKILL.md index 9855783..0ba2ca5 100644 --- a/core/skills/review-artifact/SKILL.md +++ b/core/skills/review-artifact/SKILL.md @@ -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, [org-internal #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 /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 `/{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 @@ -393,7 +396,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 /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. diff --git a/core/skills/review-code/SKILL.md b/core/skills/review-code/SKILL.md index 4b0ae9d..8fe86dc 100644 --- a/core/skills/review-code/SKILL.md +++ b/core/skills/review-code/SKILL.md @@ -974,7 +974,8 @@ 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 /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 @@ -987,7 +988,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 /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 `/{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` diff --git a/core/skills/verify/SKILL.md b/core/skills/verify/SKILL.md index 4aa2d89..f67d6b4 100644 --- a/core/skills/verify/SKILL.md +++ b/core/skills/verify/SKILL.md @@ -732,10 +732,10 @@ originating slug in each row so the trail survives. independent ticket THEN, carrying the reserved `TD-NNN`: ``` -gitea_issue__create(owner="Octopus", repo="octopus", - title="[{origin}] Tech debt: {short description} (TD-{NNN})", - body=, - labels=[tech_debt_label_id, severity_label_id]) +POST /api/v1/repos/Octopus/octopus/issues + body: {"title":"[{origin}] Tech debt: {short description} (TD-{NNN})", + "body":, + "labels":[tech_debt_label_id, severity_label_id]} ``` - **Severity → label** (reuse the existing exclusive Priority set): @@ -820,8 +820,7 @@ 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") +GET /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 @@ -848,10 +847,10 @@ number `#NNNN` is the tracker handle. no existing family matches the signature: ``` -gitea_issue__create(owner="Octopus", repo="octopus", - title="[{origin}] Baseline failure: {test identifier} (BF-{NNN})", - body=, - labels=[baseline_failure_label_id, severity_label_id, kind_bug_label_id]) +POST /api/v1/repos/Octopus/octopus/issues + body: {"title":"[{origin}] Baseline failure: {test identifier} (BF-{NNN})", + "body":, + "labels":[baseline_failure_label_id, severity_label_id, kind_bug_label_id]} ``` - **Title**: `[{origin}] Baseline failure: {signature summary} (BF-{NNN})` @@ -965,8 +964,7 @@ 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") +GET /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 / @@ -991,10 +989,10 @@ incl. closed tickets). `FT-NNN` names the FAMILY. no existing family matches the signature: ``` -gitea_issue__create(owner="Octopus", repo="octopus", - title="[{origin}] Flaky test: {test identifier} (FT-{NNN})", - body=, - labels=[flaky_test_label_id, severity_label_id, kind_testing_label_id]) +POST /api/v1/repos/Octopus/octopus/issues + body: {"title":"[{origin}] Flaky test: {test identifier} (FT-{NNN})", + "body":, + "labels":[flaky_test_label_id, severity_label_id, kind_testing_label_id]} ``` - **Title**: `[{origin}] Flaky test: {signature summary} (FT-{NNN})` — the diff --git a/package.json b/package.json index da91479..abd0ccf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ -{ +{ "name": "octopus-workflow", - "version": "0.1.0", + "version": "0.1.1", "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,