From dd24015caf9db749455e28eb6ed0ab299df9f4fd Mon Sep 17 00:00:00 2001 From: FxxkrLab <64625740+fxxkrlab@users.noreply.github.com> Date: Wed, 30 Sep 2026 20:54:01 +0900 Subject: [PATCH 1/3] chore: adopt issue-driven portfolio workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs aiStackcoding/aiStack#2 Related to https://linear.app/fxxkrlab/issue/FXX-27/流程初始化-aistack接入-issue总看板linear独立分支与-draft-pr --- .github/ISSUE_TEMPLATE/portfolio-bug.yml | 52 ++++++++++++++++ .github/ISSUE_TEMPLATE/portfolio-task.yml | 52 ++++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 27 +++++++++ .github/portfolio.json | 18 ++++++ .github/workflows/portfolio-traceability.yml | 63 ++++++++++++++++++++ AGENTS.md | 31 ++++++++++ docs/development/portfolio-workflow.md | 44 ++++++++++++++ 7 files changed, 287 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/portfolio-bug.yml create mode 100644 .github/ISSUE_TEMPLATE/portfolio-task.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/portfolio.json create mode 100644 .github/workflows/portfolio-traceability.yml create mode 100644 AGENTS.md create mode 100644 docs/development/portfolio-workflow.md diff --git a/.github/ISSUE_TEMPLATE/portfolio-bug.yml b/.github/ISSUE_TEMPLATE/portfolio-bug.yml new file mode 100644 index 0000000..138aae2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/portfolio-bug.yml @@ -0,0 +1,52 @@ +name: 缺陷 +description: 记录复现、预期、回归验收与关联 +title: "[缺陷] " +body: + - type: markdown + attributes: + value: "创建前请查重。任务创建后关联总看板和 Linear;原生同步仓库先查自动同步任务。" + - type: textarea + id: goal + attributes: + label: 复现步骤、实际结果与预期行为 + description: 写版本/平台/环境、复现步骤、预期和实际结果;请勿包含凭据或个人敏感数据 + validations: + required: true + - type: textarea + id: acceptance + attributes: + label: 验收条件 + description: 写可核验的清单,区分代码、部署与真实用户验收 + validations: + required: true + - type: textarea + id: dependencies + attributes: + label: 依赖与关联 + description: 写仓库/Issue源链接及真实阻塞;没有依赖请写无 + validations: + required: true + - type: textarea + id: verification + attributes: + label: 预期验证方式 + description: 写本地检查、指定CI/数据库环境和适用的真实用户验收 + validations: + required: true + - type: textarea + id: next + attributes: + label: 下一步 + validations: + required: true + - type: dropdown + id: priority + attributes: + label: 建议优先级 + options: + - P2 + - P0 + - P1 + - P3 + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/portfolio-task.yml b/.github/ISSUE_TEMPLATE/portfolio-task.yml new file mode 100644 index 0000000..299ef2f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/portfolio-task.yml @@ -0,0 +1,52 @@ +name: 需求 / 任务 +description: 建立目标、范围、验收、依赖与下一步 +title: "[任务] " +body: + - type: markdown + attributes: + value: "创建前请查重。任务创建后关联总看板和 Linear;原生同步仓库先查自动同步任务。" + - type: textarea + id: goal + attributes: + label: 目标与范围 + description: 说明预期行为、受影响范围和边界 + validations: + required: true + - type: textarea + id: acceptance + attributes: + label: 验收条件 + description: 写可核验的清单,区分代码、部署与真实用户验收 + validations: + required: true + - type: textarea + id: dependencies + attributes: + label: 依赖与关联 + description: 写仓库/Issue源链接及真实阻塞;没有依赖请写无 + validations: + required: true + - type: textarea + id: verification + attributes: + label: 预期验证方式 + description: 写本地检查、指定CI/数据库环境和适用的真实用户验收 + validations: + required: true + - type: textarea + id: next + attributes: + label: 下一步 + validations: + required: true + - type: dropdown + id: priority + attributes: + label: 建议优先级 + options: + - P2 + - P0 + - P1 + - P3 + validations: + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..d670dd9 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,27 @@ +## 目标与范围 + + + +## 关联 + +Refs aiStackcoding/aiStack# +Related to https://linear.app/fxxkrlab/issue/FXX-<编号>/<实际任务路径> +总看板:https://github.com/users/fxxkrlab/projects/6 +Branch: <实际分支> +Commit: <当前完整40字符SHA> + +## 验收条件 + + + +## 验证证据 + + + +## 风险与回滚 + + + +## 剩余交付步骤 + + diff --git a/.github/portfolio.json b/.github/portfolio.json new file mode 100644 index 0000000..8265b38 --- /dev/null +++ b/.github/portfolio.json @@ -0,0 +1,18 @@ +{ + "schemaVersion": 1, + "repository": "aiStackcoding/aiStack", + "product": "aiStack", + "githubProject": "https://github.com/users/fxxkrlab/projects/6", + "linear": { + "workspace": "fxxkrlab", + "team": "FXX", + "projectId": "6d5efdfa-05b0-4e96-b250-58a780ef7b64", + "projectUrl": "https://linear.app/fxxkrlab/project/跨项目研发总览-cf51cdb72517", + "issueAssociation": "manual-source-link" + }, + "bootstrapIssue": "https://github.com/aiStackcoding/aiStack/issues/2", + "bootstrapLinearIssue": "https://linear.app/fxxkrlab/issue/FXX-27/流程初始化-aistack接入-issue总看板linear独立分支与-draft-pr", + "defaultPullRequest": "draft", + "completionRequires": "all-issue-acceptance-criteria", + "branchProtection": "verify-plan-and-required-checks-before-enabling" +} diff --git a/.github/workflows/portfolio-traceability.yml b/.github/workflows/portfolio-traceability.yml new file mode 100644 index 0000000..0ad4043 --- /dev/null +++ b/.github/workflows/portfolio-traceability.yml @@ -0,0 +1,63 @@ +name: Portfolio traceability +on: + pull_request: + types: [opened, reopened, edited, synchronize, ready_for_review] +permissions: + contents: read + issues: read + pull-requests: read +jobs: + traceability: + name: traceability + runs-on: ubuntu-latest + timeout-minutes: 3 + steps: + - name: Verify task and delivery references + env: + GH_TOKEN: ${{ github.token }} + shell: bash + run: | + node --input-type=module <<'PORTFOLIO_NODE' + export function inspectPullRequest(pr, repository) { + const errors = []; + const branch = pr.head?.ref || ''; + const match = /^codex\/(?:fxx-(\d+)-)?gh-(\d+)-[a-z0-9][a-z0-9-]*$/.exec(branch); + if (!match) errors.push('Use codex/fxx-N-gh-N-description (or codex/gh-N-description while the Linear number is pending).'); + const body = String(pr.body || '').replace(//g, ''); + const escaped = repository.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const refs = [...body.matchAll(new RegExp(`\\bRefs\\s+${escaped}#(\\d+)\\b`, 'gi'))]; + const issueNumber = match ? Number(match[2]) : 0; + if (!refs.some(x => Number(x[1]) === issueNumber)) errors.push('Refs must identify the branch ticket in this repository.'); + const linear = /https:\/\/linear\.app\/fxxkrlab\/issue\/FXX-(\d+)(?:\/[^\s)>]*)?/i.exec(body); + if (!linear) errors.push('Include the actual FXX Linear issue URL.'); + if (match?.[1] && linear && Number(match[1]) !== Number(linear[1])) errors.push('The branch Linear number and Linear link differ.'); + if (!body.includes('https://github.com/users/fxxkrlab/projects/6')) errors.push('Include the portfolio board URL; membership is verified separately.'); + if (!body.includes(`Branch: ${branch}`)) errors.push('Record the actual Branch: value.'); + if (!pr.head?.sha || !body.includes(`Commit: ${pr.head.sha}`)) errors.push('Record the current 40-character head SHA in Commit:.'); + for (const heading of ['目标与范围', '验收条件', '验证证据', '风险与回滚', '剩余交付步骤']) { + const section = new RegExp(`^## ${heading}\\s*\\n([\\s\\S]*?)(?=^## |$(?![\\s\\S]))`, 'm').exec(body); + const value = section?.[1]?.trim() || ''; + if (!value || /^(?:待填写|TBD|TODO|<[^>]+>)$/i.test(value)) errors.push(`Complete section: ${heading}.`); + } + return {errors, issueNumber}; + } + + export async function verifyIssue(repository, number, request) { + const response = await request(`https://api.github.com/repos/${repository}/issues/${number}`); + if (!response.ok) throw new Error(`Unable to verify source Issue: HTTP ${response.status}.`); + const issue = await response.json(); + if (issue.pull_request || issue.number !== number || issue.html_url?.toLowerCase() !== `https://github.com/${repository}/issues/${number}`.toLowerCase()) throw new Error('The source must be an actual Issue in this repository.'); + if (issue.state !== 'open') throw new Error('Use an open delivery Issue; completed work requires a new task.'); + return issue; + } + + import fs from 'node:fs'; + const event = JSON.parse(fs.readFileSync(process.env.GITHUB_EVENT_PATH, 'utf8')); + const result = inspectPullRequest(event.pull_request, process.env.GITHUB_REPOSITORY); + if (result.errors.length) { console.error(result.errors.join('\n')); process.exit(1); } + await verifyIssue(process.env.GITHUB_REPOSITORY, result.issueNumber, url => fetch(url, { + headers: {accept:'application/vnd.github+json',authorization:`Bearer ${process.env.GH_TOKEN}`,'X-GitHub-Api-Version':'2022-11-28'}, + redirect:'error',signal:AbortSignal.timeout(15000) + })); + console.log('PR metadata and source Issue verified. Linear membership, board membership and delivery evidence require separate readback/review.'); + PORTFOLIO_NODE diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..4d2c0b4 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,31 @@ +# Codex 默认项目交付流程 + +## 适用范围与授权 +这些规则是用户于 2026-09-30 要求为现有及未来新增项目建立的默认流程,适用于实施功能、修复缺陷、项目配置和交付文档的工作。普通问答、只读排查、翻译和单次文档处理不必人为创建工程工单。尊重当前任务的更具体限制、既有发布负责人及指定验证环境。 + +## 开始实施前 +1. 核对真实 Git 根目录、GitHub owner/repo、当前分支、未提交改动和适用 AGENTS 文件。不得把聊天中的目录名当成真实仓库归属。 +2. 找到对应 GitHub Issue;没有时先查重再创建。写清目标、范围、验收条件、依赖、预期验证方式和下一步。日常任务追踪属于用户授权的工作,不要反复请求创建工单的确认。 +3. 将 Issue 纳入 [跨项目研发总看板](https://github.com/users/fxxkrlab/projects/6),设置项目、优先级和工作类型;未核验状态使用“待整理 / 待核验”。 +4. 关联 Linear 工作区 fxxkrlab、团队 FXX 及“跨项目研发总览”项目。对已配置 GitHub → Linear 新任务同步的仓库,先查到自动同步的 Issue,再关联项目;不得另建重复镜像。未配置同步的仓库创建一个有 GitHub 源链接的 Linear 关联任务,并明确当前同步方式。 +5. 跨仓库工作建立协调 Issue 和各仓库实施 Issue,用显式链接及真实阻塞关系连接;不要仅保留在 Codex 聊天里。 + +## 分支、提交与 PR +- 在用户指定或新建的独立工作分支/worktree 开发,保护现有未提交改动。不得在默认分支直接实施或直接推送。 +- 新分支采用 codex/fxx--gh--<简短描述>;同步尚未提供 Linear 编号时可先采用 codex/gh--<简短描述>,随后记录关联。 +- 提交和 PR 必须引用对应 GitHub Issue。PR 正文还须含真实 Linear 链接、分支/提交、验收条件、验证证据、风险和仍需完成的交付步骤。 +- 默认创建 Draft PR 供集中审查;遵守当前任务的推送限制。用户限定本地/禁止推送时交付本地提交及后续命令,不绕过限制。 +- 完成工作后把 PR 加入总看板并更新对应任务。GitHub Issue、PR、Linear 任务采用明确链接,不凭相似标题猜测关联。 +- PR 中使用 “Refs owner/repo#N” 及 “Related to ” 保留交付任务;需要部署/启用/真实用户验收的 Issue 不使用自动关闭关键词代替验收。 +- 合并、发布、部署、生产启用以及外部资金/通知动作,仍由用户的明确操作授权和指定负责人控制;初始化流程不授权这些动作。 + +## 证据与状态 +- 分别记录本地/静态验证、指定服务器 CI/数据库验证、已合并、已部署、已启用和真实用户/客户端验收。PR 合并不代表已经部署或验收。 +- 仅在本 Issue 的全部验收条件满足后标记完成;整理任务按其文档验收范围判定,不能据此宣称产品交付。 +- 有阻塞时写明原因、解除阻塞所需证据和下一步;环境失败、未知状态和未执行检查不标记通过。 +- 原生 GitHub–Linear 集成不自动同步 Projects 自定义状态。根据实际证据分别维护这些字段,不宣称未验证的自动化已经生效。 + +## 新项目接入 +首次实施新项目时完成相同的仓库核对、Issue、总看板、Linear、独立分支和 Draft PR 流程。优先复用既有仓库,尊重用户指定的 owner、可见性和名称;没有远端时先确认仓库归属与可见性,不将私有内容公开。 +通过专门的初始化 Issue 和独立 PR 添加任务/缺陷模板、PR 模板、仓库流程说明及必要的追踪检查;保留原有 AGENTS、模板和 CI。GitHub App 未获新组织/仓库权限时报告准确缺口,不擅自扩大代码访问。 +本仓库接入数据位于 `.github/portfolio.json`,完整说明见 `docs/development/portfolio-workflow.md`。平台分支保护能力须现场核验;当前私有仓库套餐限制不能通过改公开或虚报保护生效来绕过。 diff --git a/docs/development/portfolio-workflow.md b/docs/development/portfolio-workflow.md new file mode 100644 index 0000000..fd92bef --- /dev/null +++ b/docs/development/portfolio-workflow.md @@ -0,0 +1,44 @@ +# 项目交付与追踪流程 + +仓库:`aiStackcoding/aiStack`。GitHub Issue 保存任务的目标、范围、验收与证据;[跨项目研发总看板](https://github.com/users/fxxkrlab/projects/6) 汇总跨仓库工作;[Linear 跨项目研发总览](https://linear.app/fxxkrlab/project/跨项目研发总览-cf51cdb72517) 关联规划与依赖。 + +## 开始一项工作 + +1. 核对真实 Git 根目录、远端归属、当前分支、未提交改动及适用 AGENTS;保护现有工作区。 +2. 在本仓库按目标和源链接查重,然后复用或新建 Issue。写明范围、验收条件、依赖、预期验证环境和下一步。普通问答与只读排查无需人为创建工程工单。 +3. 将 Issue 加入总看板,填写项目、优先级、工作类型;未知状态使用“待整理 / 待核验”。 +4. 关联 Linear 工作区 fxxkrlab、团队 FXX、本项目。当前 GitHub App 未连接 aiStackcoding 组织,采用有 GitHub 源 Issue 链接的手动 Linear 关联。尚未配置原生自动同步;补接 App 后先按源链接去重,不扩大代码访问权限。 +5. 从核验的基线创建独立分支/worktree。使用 `codex/fxx-<数字>-gh--<简短描述>`;同步尚未提供编号时先用 `codex/gh--<简短描述>`,获得 Linear 编号后记录准确链接。 + +## 提交与 PR + +提交引用 `Refs aiStackcoding/aiStack#N`。默认创建 Draft PR;正文填写真实 Linear Issue URL、分支、当前完整 head SHA、目标、验收条件、验证证据、风险/回滚和剩余交付步骤。使用 `Related to ` 保留任务关联,需要部署或真实用户验收的任务避免自动关闭关键词。 + +将 PR 加入总看板,并更新 Issue 与 Linear 的明确链接。跨仓库工作建立协调 Issue 和双方实施 Issue,实际阻塞关系写明解除所需证据;不能仅凭相似标题关联。 + +仓库的 `Portfolio traceability / traceability` 检查验证分支中的 GitHub/Linear 编号、同仓库的开放 Issue、实际 head SHA 及 PR 说明。它只读取事件和 GitHub Issue API,使用只读 GITHUB_TOKEN,无 checkout、部署或业务操作。旧 PR 后续触发检查时也需补齐流程;在迁移前保留旧分支和已有证据,通过独立任务决定迁移方式。 + +该检查验证 Linear/总看板链接格式与正文信息;它没有跨产品凭据,**不能证明 Linear 任务存在、关联正确、总看板成员关系或验收证据真实**。这些内容由执行者回读核验并由审查人确认;GitHub App 未获权限时记录缺口。不能用一条绿色元数据检查代替原有产品 CI。 + +## 状态与完成 + +总看板:待整理 → 待开发 → 开发中 → 待审核 → 待合并 → 待部署 → 待验收 → 完成;按实际任务跳过不适用阶段,阻塞时填写原因、解除证据和下一步。 + +证据分别记录本地/静态、指定服务器 CI/数据库、合并、部署、启用与真实用户/客户端验收。未知、未执行和环境失败不标记通过。仅本 Issue 的全部验收条件满足后关闭 Issue 并完成 Linear 任务;文档整理验收不能计为产品发布。 + +原生 GitHub–Linear 集成不负责 GitHub Projects 自定义状态。原生同步 Issue 的标题/描述/开放关闭变化可能双向传播;将状态更新视为真实变更,只在相应验收满足后关闭,不用 PR 合并替代交付完成。 + +合并、发布、部署、生产启用和外部资金/通知动作仍需明确操作授权及指定负责人。默认分支保护和 required check 只有平台实际允许、配置成功且回读核验后才能记为生效;当前套餐限制不能通过公开私有仓库绕过。PR 检查本身不阻止直接推送。 + +## 后续新增项目 + +首次实施前复用真实仓库并完成相同核对、去重 Issue、总看板、Linear、独立分支和 Draft PR 接入。没有远端时先确认 owner、名称和可见性。用专门初始化 Issue/PR 添加这些模板与规则,保留既有 AGENTS、模板和 CI,核验新仓库的 App 权限与关联方式。全局 Codex 规则指导本机未来项目;团队成员和其他设备通过仓库 AGENTS/模板继承。 + +## 本次初始化 + +- GitHub:https://github.com/aiStackcoding/aiStack/issues/2 +- Linear:https://linear.app/fxxkrlab/issue/FXX-27/流程初始化-aistack接入-issue总看板linear独立分支与-draft-pr +- 关联方式:`manual-source-link` +- 合并后核验默认分支模板和工作流;本初始化不会关闭产品交付任务。 + +技术参考:[GitHub GITHUB_TOKEN 权限](https://docs.github.com/en/actions/tutorials/authenticate-with-github_token)、[Issues API](https://docs.github.com/en/rest/issues/issues)、[Linear GitHub 集成](https://linear.app/docs/github)。 From de2a31abfd061916ebfeffbf6352c6825b9c9aef Mon Sep 17 00:00:00 2001 From: FxxkrLab <64625740+fxxkrlab@users.noreply.github.com> Date: Wed, 30 Sep 2026 21:05:15 +0900 Subject: [PATCH 2/3] chore: mark portfolio instructions for safe upkeep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs aiStackcoding/aiStack#2 Related to https://linear.app/fxxkrlab/issue/FXX-27/流程初始化-aistack接入-issue总看板linear独立分支与-draft-pr --- AGENTS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 4d2c0b4..b51fa1f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,3 +1,4 @@ + # Codex 默认项目交付流程 ## 适用范围与授权 @@ -29,3 +30,4 @@ 首次实施新项目时完成相同的仓库核对、Issue、总看板、Linear、独立分支和 Draft PR 流程。优先复用既有仓库,尊重用户指定的 owner、可见性和名称;没有远端时先确认仓库归属与可见性,不将私有内容公开。 通过专门的初始化 Issue 和独立 PR 添加任务/缺陷模板、PR 模板、仓库流程说明及必要的追踪检查;保留原有 AGENTS、模板和 CI。GitHub App 未获新组织/仓库权限时报告准确缺口,不擅自扩大代码访问。 本仓库接入数据位于 `.github/portfolio.json`,完整说明见 `docs/development/portfolio-workflow.md`。平台分支保护能力须现场核验;当前私有仓库套餐限制不能通过改公开或虚报保护生效来绕过。 + From 3d456cda38675dc7a2e03b6d57c359ab5d9e1d24 Mon Sep 17 00:00:00 2001 From: FxxkrLab <64625740+fxxkrlab@users.noreply.github.com> Date: Wed, 30 Sep 2026 21:11:14 +0900 Subject: [PATCH 3/3] fix: validate current PR metadata and supersede stale events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs aiStackcoding/aiStack#2 Related to https://linear.app/fxxkrlab/issue/FXX-27/流程初始化-aistack接入-issue总看板linear独立分支与-draft-pr --- .github/workflows/portfolio-traceability.yml | 21 ++++++++++++++++---- docs/development/portfolio-workflow.md | 2 +- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/.github/workflows/portfolio-traceability.yml b/.github/workflows/portfolio-traceability.yml index 0ad4043..8f89c02 100644 --- a/.github/workflows/portfolio-traceability.yml +++ b/.github/workflows/portfolio-traceability.yml @@ -6,6 +6,9 @@ permissions: contents: read issues: read pull-requests: read +concurrency: + group: portfolio-traceability-${{ github.event.pull_request.number }} + cancel-in-progress: true jobs: traceability: name: traceability @@ -18,6 +21,11 @@ jobs: shell: bash run: | node --input-type=module <<'PORTFOLIO_NODE' + export function currentPullRequestForEvent(eventPr, currentPr) { + if (eventPr.number !== currentPr.number) throw new Error('The current PR differs from the triggering PR.'); + return eventPr.head?.sha === currentPr.head?.sha ? currentPr : null; + } + export function inspectPullRequest(pr, repository) { const errors = []; const branch = pr.head?.ref || ''; @@ -53,11 +61,16 @@ jobs: import fs from 'node:fs'; const event = JSON.parse(fs.readFileSync(process.env.GITHUB_EVENT_PATH, 'utf8')); - const result = inspectPullRequest(event.pull_request, process.env.GITHUB_REPOSITORY); - if (result.errors.length) { console.error(result.errors.join('\n')); process.exit(1); } - await verifyIssue(process.env.GITHUB_REPOSITORY, result.issueNumber, url => fetch(url, { + const request = url => fetch(url, { headers: {accept:'application/vnd.github+json',authorization:`Bearer ${process.env.GH_TOKEN}`,'X-GitHub-Api-Version':'2022-11-28'}, redirect:'error',signal:AbortSignal.timeout(15000) - })); + }); + const response = await request(`https://api.github.com/repos/${process.env.GITHUB_REPOSITORY}/pulls/${event.pull_request.number}`); + if (!response.ok) throw new Error(`Unable to read current PR: HTTP ${response.status}.`); + const current = currentPullRequestForEvent(event.pull_request, await response.json()); + if (!current) { console.log('Superseded head; this event does not validate the current delivery.'); process.exit(0); } + const result = inspectPullRequest(current, process.env.GITHUB_REPOSITORY); + if (result.errors.length) { console.error(result.errors.join('\n')); process.exit(1); } + await verifyIssue(process.env.GITHUB_REPOSITORY, result.issueNumber, request); console.log('PR metadata and source Issue verified. Linear membership, board membership and delivery evidence require separate readback/review.'); PORTFOLIO_NODE diff --git a/docs/development/portfolio-workflow.md b/docs/development/portfolio-workflow.md index fd92bef..4272ed6 100644 --- a/docs/development/portfolio-workflow.md +++ b/docs/development/portfolio-workflow.md @@ -16,7 +16,7 @@ 将 PR 加入总看板,并更新 Issue 与 Linear 的明确链接。跨仓库工作建立协调 Issue 和双方实施 Issue,实际阻塞关系写明解除所需证据;不能仅凭相似标题关联。 -仓库的 `Portfolio traceability / traceability` 检查验证分支中的 GitHub/Linear 编号、同仓库的开放 Issue、实际 head SHA 及 PR 说明。它只读取事件和 GitHub Issue API,使用只读 GITHUB_TOKEN,无 checkout、部署或业务操作。旧 PR 后续触发检查时也需补齐流程;在迁移前保留旧分支和已有证据,通过独立任务决定迁移方式。 +仓库的 `Portfolio traceability / traceability` 检查验证分支中的 GitHub/Linear 编号、同仓库的开放 Issue、实际 head SHA 及 PR 说明。它只读取事件和当前 GitHub PR/Issue API,使用只读 GITHUB_TOKEN,无 checkout、部署或业务操作。读取当前 PR 正文避免提交和正文先后更新引发旧事件误报;并发取消过期作业,已被新 head 替代的事件不验证当前交付。旧 PR 后续触发检查时也需补齐流程;在迁移前保留旧分支和已有证据,通过独立任务决定迁移方式。 该检查验证 Linear/总看板链接格式与正文信息;它没有跨产品凭据,**不能证明 Linear 任务存在、关联正确、总看板成员关系或验收证据真实**。这些内容由执行者回读核验并由审查人确认;GitHub App 未获权限时记录缺口。不能用一条绿色元数据检查代替原有产品 CI。