Define iterative delivery with explicit stage reviews #227
File diff suppressed because one or more lines are too long
@@ -0,0 +1,257 @@
|
||||
{
|
||||
"status": "complete",
|
||||
"verdict": "Ready with fixes",
|
||||
"verdict_reason": "R1-R10 are addressed. One confirmed P3 needs a localized template/reference fix; there are no P0-P2 findings. This source review does not establish platform merge readiness: no GATE was verified.",
|
||||
"scope": {
|
||||
"mode": "branch-remote",
|
||||
"base": "2147d5cb6566c301eaea3c65448bdda873093aea",
|
||||
"branch": "feature/iterative-delivery",
|
||||
"head_sha": "125e159924d90954c3bafc8572cc260e1e12eadc",
|
||||
"pr_url": null,
|
||||
"files_changed": 9
|
||||
},
|
||||
"intent": "Make Dev delivery iterative with ten stages and a requirements/fit table; default to stage-by-stage human review while honoring explicit scoped continuous authorization. Align generated task cards, entrypoint docs, and capability matrix; remove implicit task closure writes from post-merge without weakening safe cleanup or claiming manual approvals are machine verified.",
|
||||
"intent_confidence": "explicit",
|
||||
"reviewers": [
|
||||
"correctness",
|
||||
"project-standards",
|
||||
"testing",
|
||||
"agent-native",
|
||||
"adversarial"
|
||||
],
|
||||
"findings": [
|
||||
{
|
||||
"#": 1,
|
||||
"autofix_class": "gated_auto",
|
||||
"confidence": 100,
|
||||
"evidence": [
|
||||
"scripts/task.sh:184 -- - 流程依据:[policy/delivery.md](../policy/delivery.md)",
|
||||
"scripts/task.sh:322-340 -- card_backfill updates status and main record, then appends closure notes; it does not rewrite relative links.",
|
||||
"scripts/task.sh:391 and 401 -- git mv \"$c\" \".task/archive/${c##*/}\"",
|
||||
"git ls-tree 125e159924d90954c3bafc8572cc260e1e12eadc:.task contains no policy subtree; policy/delivery.md exists at repository root."
|
||||
],
|
||||
"file": "scripts/task.sh",
|
||||
"first_evidence": "scripts/task.sh:184 -- - 流程依据:[policy/delivery.md](../policy/delivery.md)",
|
||||
"independent_reviewers": [],
|
||||
"line": 184,
|
||||
"owner": "downstream-resolver",
|
||||
"pre_existing": false,
|
||||
"requires_verification": true,
|
||||
"reviewers": [
|
||||
"scope-audit"
|
||||
],
|
||||
"severity": "P3",
|
||||
"suggested_fix": "Use a plain-text repository-root reference, such as 流程依据:仓库根目录 policy/delivery.md, in the generated card and update its template assertion. This keeps the reference meaningful in both active and archived cards without modifying the generic archive mechanism.",
|
||||
"title": "Keep the delivery reference valid after task archival",
|
||||
"why_it_matters": "Every newly generated card has a working link while stored in .task/, but normal task-close moves it into .task/archive/ and leaves the link unchanged. The link then resolves to the nonexistent .task/policy/delivery.md, so historical task cards lose their clickable policy reference. A plain-text repository-root reference avoids dependence on the card directory.",
|
||||
"validation_status": "confirmed",
|
||||
"validation_reason": "The diff newly adds scripts/task.sh:184's ../policy/delivery.md link, while scripts/task.sh:391 and :401 move every closed card from .task/ to .task/archive/ without rewriting it, so it resolves to the absent .task/policy/delivery.md at reviewed head (the root policy/delivery.md exists); this occurs whenever a new task card is closed, and tests/test_task.py:605 only checks the pre-archive form.",
|
||||
"protected_subject": null
|
||||
}
|
||||
],
|
||||
"actionable_findings": [
|
||||
{
|
||||
"#": 1,
|
||||
"autofix_class": "gated_auto",
|
||||
"confidence": 100,
|
||||
"evidence": [
|
||||
"scripts/task.sh:184 -- - 流程依据:[policy/delivery.md](../policy/delivery.md)",
|
||||
"scripts/task.sh:322-340 -- card_backfill updates status and main record, then appends closure notes; it does not rewrite relative links.",
|
||||
"scripts/task.sh:391 and 401 -- git mv \"$c\" \".task/archive/${c##*/}\"",
|
||||
"git ls-tree 125e159924d90954c3bafc8572cc260e1e12eadc:.task contains no policy subtree; policy/delivery.md exists at repository root."
|
||||
],
|
||||
"file": "scripts/task.sh",
|
||||
"first_evidence": "scripts/task.sh:184 -- - 流程依据:[policy/delivery.md](../policy/delivery.md)",
|
||||
"independent_reviewers": [],
|
||||
"line": 184,
|
||||
"owner": "downstream-resolver",
|
||||
"pre_existing": false,
|
||||
"requires_verification": true,
|
||||
"reviewers": [
|
||||
"scope-audit"
|
||||
],
|
||||
"severity": "P3",
|
||||
"suggested_fix": "Use a plain-text repository-root reference, such as 流程依据:仓库根目录 policy/delivery.md, in the generated card and update its template assertion. This keeps the reference meaningful in both active and archived cards without modifying the generic archive mechanism.",
|
||||
"title": "Keep the delivery reference valid after task archival",
|
||||
"why_it_matters": "Every newly generated card has a working link while stored in .task/, but normal task-close moves it into .task/archive/ and leaves the link unchanged. The link then resolves to the nonexistent .task/policy/delivery.md, so historical task cards lose their clickable policy reference. A plain-text repository-root reference avoids dependence on the card directory.",
|
||||
"validation_status": "confirmed",
|
||||
"validation_reason": "The diff newly adds scripts/task.sh:184's ../policy/delivery.md link, while scripts/task.sh:391 and :401 move every closed card from .task/ to .task/archive/ without rewriting it, so it resolves to the absent .task/policy/delivery.md at reviewed head (the root policy/delivery.md exists); this occurs whenever a new task card is closed, and tests/test_task.py:605 only checks the pre-archive form.",
|
||||
"protected_subject": null
|
||||
}
|
||||
],
|
||||
"triage_groups": [],
|
||||
"pre_existing_findings": [],
|
||||
"requirements_completeness": {
|
||||
"plan_source": "explicit",
|
||||
"plan": ".task/feature-iterative-delivery.md",
|
||||
"requirements": [
|
||||
{
|
||||
"id": "R1",
|
||||
"status": "met",
|
||||
"assessment": "Ten stages name their artifacts and exits.",
|
||||
"evidence": "policy/delivery.md: stages and exits"
|
||||
},
|
||||
{
|
||||
"id": "R2",
|
||||
"status": "met",
|
||||
"assessment": "Generated cards include stable requirement IDs, fit evidence, acceptance criteria and disposition.",
|
||||
"evidence": "scripts/task.sh: requirement table"
|
||||
},
|
||||
{
|
||||
"id": "R3",
|
||||
"status": "met",
|
||||
"assessment": "Manual review defaults and scoped continuous authorization are explicit; templates start unreviewed.",
|
||||
"evidence": "policy/delivery.md: authorization; scripts/task.sh: stage review table"
|
||||
},
|
||||
{
|
||||
"id": "R4",
|
||||
"status": "met",
|
||||
"assessment": "Design, implementation and test plans retain versioned approval objects, assumptions and verification methods.",
|
||||
"evidence": "policy/delivery.md: stages, exploration and feedback loops"
|
||||
},
|
||||
{
|
||||
"id": "R5",
|
||||
"status": "met",
|
||||
"assessment": "Four impact classes determine continuation, revision and renewed review.",
|
||||
"evidence": "policy/delivery.md: feedback-loop impact table"
|
||||
},
|
||||
{
|
||||
"id": "R6",
|
||||
"status": "met",
|
||||
"assessment": "Post-merge defaults to reminders; governance tests exercise real merge/pull without closure writes.",
|
||||
"evidence": "scripts/hooks/post-merge; tests/test_task.py; independent local replay"
|
||||
},
|
||||
{
|
||||
"id": "R7",
|
||||
"status": "met",
|
||||
"assessment": "Merge and cleanup exits preserve registered-workspace, writer and unique-file checks, with receipts outside deleted workspaces.",
|
||||
"evidence": "policy/delivery.md: merge, cleanup and recovery; policy/governance.md"
|
||||
},
|
||||
{
|
||||
"id": "R8",
|
||||
"status": "met",
|
||||
"assessment": "Entrypoint, adoption records, generated cards and capability classifications align; governance replay passed. Finding #1 is a narrow archival-reference defect.",
|
||||
"evidence": "AGENTS.md; policy/adoption.md; policy/tool-adaptation-matrix.md; scripts/task.sh"
|
||||
},
|
||||
{
|
||||
"id": "R9",
|
||||
"status": "met",
|
||||
"assessment": "Bounded experiments can precede complete design, with explicit approval and separate acceptance.",
|
||||
"evidence": "policy/delivery.md: design exploration loop"
|
||||
},
|
||||
{
|
||||
"id": "R10",
|
||||
"status": "met",
|
||||
"assessment": "Incremental work records discoveries, adjustments, renewed review/tests, decisions, outcomes and stopping conditions.",
|
||||
"evidence": "policy/delivery.md: feedback loops; scripts/task.sh: exploration and iteration table"
|
||||
}
|
||||
],
|
||||
"implementation_units": []
|
||||
},
|
||||
"learnings": [],
|
||||
"agent_native_gaps": [],
|
||||
"deployment_notes": [],
|
||||
"residual_risks": [],
|
||||
"testing_gaps": [
|
||||
"Full application suite and build were not rerun at the reviewed head; the reported earlier author run is not independently verified.",
|
||||
"Remote PR CI and GATE identity/SHA were not verified.",
|
||||
"The later uncommitted archival-reference fix and assertion were not reviewed or verified."
|
||||
],
|
||||
"coverage": {
|
||||
"notes": [
|
||||
"Reviewed only the nine-file diff between fixed base and head; main checkout source was not used for changed files. Full roster selected because instruction prose and changed tests rule out lite coverage.",
|
||||
"Project standards used root AGENTS.md as instruction fallback; no CODING_STANDARDS.md applies. No matching solutions corpus or declared local pack was selected.",
|
||||
"Independent replay by /root/delivery_review at fixed head 125e159924d90954c3bafc8572cc260e1e12eadc: make test-governance && git diff --check; exit 0, 104 tests passed. Receipt /tmp/iterative-delivery-review-replay-20261007.json remains source SELF; local evidence does not authenticate CI or reviewer identity.",
|
||||
"Full application suite and build were not rerun by this review. Author reported they passed on 9454819 with only task metadata changed afterward; remote PR CI is not yet available and is not validated by this review.",
|
||||
"Supplemental scope-audit is a non-independent source inspection; the five dispatched specialist reviewers returned no findings.",
|
||||
"The root caller is preparing the minimal archival-reference fix outside the fixed review head. Review does not claim that uncommitted fix verified."
|
||||
],
|
||||
"reviewer_selection": [
|
||||
{
|
||||
"reviewer": "correctness",
|
||||
"tier": "session",
|
||||
"reason": "always-on"
|
||||
},
|
||||
{
|
||||
"reviewer": "project-standards",
|
||||
"tier": "mid",
|
||||
"reason": "AGENTS.md governs all changed files"
|
||||
},
|
||||
{
|
||||
"reviewer": "testing",
|
||||
"tier": "mid",
|
||||
"reason": "real-Git hook tests and generated task-card assertions changed"
|
||||
},
|
||||
{
|
||||
"reviewer": "agent-native",
|
||||
"tier": "mid",
|
||||
"reason": "agent instructions, commands and task-card context changed"
|
||||
},
|
||||
{
|
||||
"reviewer": "adversarial",
|
||||
"tier": "session",
|
||||
"reason": "post-merge persistence side effects and command composition changed"
|
||||
}
|
||||
],
|
||||
"lite": false,
|
||||
"cross_model": {
|
||||
"outcome": "in-process-fallback",
|
||||
"note": "Independent external cross-model pass not run: branch-remote scope uses the local adversarial reviewer against fixed refs. No code sent externally."
|
||||
},
|
||||
"validator": {
|
||||
"outcome": "verdicts",
|
||||
"batches": 1,
|
||||
"confirmed": 1,
|
||||
"rejected": 0,
|
||||
"unresolved": 0,
|
||||
"malformed": 0,
|
||||
"failed": 0,
|
||||
"shortcut_skipped": 0,
|
||||
"shortcut_basis": "No verified independent cross-model corroboration.",
|
||||
"bound_exceeded": false,
|
||||
"results": [
|
||||
{
|
||||
"#": 1,
|
||||
"status": "confirmed",
|
||||
"protected_subject": null,
|
||||
"reason": "The diff newly adds scripts/task.sh:184's ../policy/delivery.md link, while scripts/task.sh:391 and :401 move every closed card from .task/ to .task/archive/ without rewriting it, so it resolves to the absent .task/policy/delivery.md at reviewed head (the root policy/delivery.md exists); this occurs whenever a new task card is closed, and tests/test_task.py:605 only checks the pre-archive form."
|
||||
}
|
||||
],
|
||||
"protected_subject_reclassifications": 0,
|
||||
"degraded_blockers": []
|
||||
},
|
||||
"suppressed_by_confidence": {},
|
||||
"malformed_findings": 0,
|
||||
"malformed_returns": 0,
|
||||
"mode_aware_demotions": 0,
|
||||
"missing_first_evidence_demotions": 0,
|
||||
"first_evidence_backfilled": 0,
|
||||
"settlement_evaluated": true,
|
||||
"settlement_suppressed": 0,
|
||||
"non_independent_attributed_sources": [
|
||||
"scope-audit"
|
||||
],
|
||||
"confidence_basis": "Direct fixed-head source evidence; no confidence promotion from scope-audit attribution or validator agreement.",
|
||||
"independent_replay": {
|
||||
"source": "SELF",
|
||||
"reviewer": "/root/delivery_review",
|
||||
"reviewer_identity_authenticated": false,
|
||||
"head_sha": "125e159924d90954c3bafc8572cc260e1e12eadc",
|
||||
"command": "make test-governance && git diff --check",
|
||||
"exit_code": 0,
|
||||
"tests_passed": 104,
|
||||
"receipt": "/tmp/iterative-delivery-review-replay-20261007.json"
|
||||
},
|
||||
"gate_verified": false,
|
||||
"failed_reviewers": [],
|
||||
"bound_exceeded": [],
|
||||
"compound_packs": {
|
||||
"roots": [],
|
||||
"errors": [],
|
||||
"warnings": []
|
||||
},
|
||||
"apply": "Skipped: agent report-only; later author edits are outside the fixed review head."
|
||||
},
|
||||
"artifact_path": "/tmp/compound-engineering-1000/ce-code-review/20261007-025812-7b611869",
|
||||
"run_id": "20261007-025812-7b611869"
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
# Agent 工作说明(Agent-System-Dev)
|
||||
|
||||
本仓开发遵循 Development-Guidelines(见 `deps/development-guidelines`,gitlink 固定版本):
|
||||
核心规则与术语见其 `core/`,按任务触发阅读 `standards/` 专题;日常交付走 `workflows/delivery.md`。
|
||||
核心规则与术语见其 `core/`,按任务触发阅读 `standards/` 专题;通用交付依据为 `workflows/delivery.md`。
|
||||
本项目的需求、设计试验、实施调整及交付**必读 [policy/delivery.md](policy/delivery.md)**:
|
||||
默认逐阶段人工评审,阶段内迭代、按影响回退;仅在用户明确授权范围内连续推进。
|
||||
|
||||
## UI 设计门禁(强制)
|
||||
|
||||
@@ -37,9 +39,8 @@
|
||||
`make task-finish ABANDON="--abandon <原因>"` 并记录原因;放弃不豁免现场保护。
|
||||
- **任务卡闭合(防欠账)**:分支合入 main 后,其任务卡须回填"已完成"+主记录 PR 链接并
|
||||
归档至 `.task/archive/`。`task-finish` 回收后提示所有者运行 `make task-close`,不借回收修改
|
||||
共享主检出或推送另一任务。自动路径保留主检出 pull 触发 post-merge
|
||||
钩子(实测 ff-only pull 也触发);钩子内 close 只扫主检出本地 `.task/`,远端刚合入的卡片
|
||||
要等 pull 完成才能被看到,扫不到时由手动 `make task-close` 兜底。手动闭合在主检出运行→建
|
||||
共享主检出或推送另一任务。主检出 pull/merge 的 post-merge 钩子仅提示待办,不自动写入或推送。
|
||||
`make task-close` 会提交、推送并可能创建 PR,须先核对闭合范围和对应授权。闭合在主检出运行→建
|
||||
`feature/card-close-*` 分支+PR,任务分支内加 `FOLD=--fold` 随当前 PR 合入。
|
||||
precheck 的 `[cards]` 行报告欠账,验收前应清零;闭合 PR 由所有者合入。
|
||||
|
||||
@@ -102,5 +103,5 @@
|
||||
- **SSH key**:`~/.ssh/home_gitea`(ED25519,公钥指纹
|
||||
`SHA256:GYXaOXIMeloQ1fKSfdJ/ndgPQzs/Ix7Hk62ekfkfQ20`,Gitea 侧密钥名 GMKtec);
|
||||
`~/.ssh/config` 已有 `git-ssh.u1680832.nyat.app` 主机条目,克隆/推送直接可用。
|
||||
- 任务卡闭合 PR(`make task-close` / `task-finish` 自动闭合)经 API 建 PR 时以
|
||||
- 任务卡闭合 PR(获授权后运行 `make task-close`)经 API 建 PR 时以
|
||||
`GITEA_TOKEN` 环境变量传入同上的 token。
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
| standards/verification.md | 验收 | 本地 make test-governance + 组合测试;当前证据与历史 scratch 记录分开 |
|
||||
| standards/multi-repo.md | 跨仓/gitlink | manual;受控历史迁移通道已于 2026-09-30 行使一次(documents/records/2026-09-30-history-migration.md) |
|
||||
| 工作区回收 | 交付终点 | advisory(task-finish);负例:合入前 finish 拒绝输出 |
|
||||
| policy/delivery.md(项目收紧) | 需求、试验、实施迭代及交付 | manual:人工评审和有范围的连续推进授权;任务卡提供记录,post-merge 默认只提示,行为回归见 tests/test_task.py |
|
||||
| standards/tool-adaptation.md(draft.8) | 为工具创建规则/钩子实例 | 本组合 CLI/git 级实例已登记:policy/tool-adaptation-matrix.md(A1–A7 逐行定级+正负例证据) |
|
||||
| 同上(zcode 实例) | zcode 客户端写路径 | policy/tool-adaptation-zcode.md:PreToolUse 写守卫;脚本负例与客户端接线分开,客户端 pending-live |
|
||||
| core/baseline.md「规范层级」+ documentation.md「记忆分层/机制化」(draft.9) | 层级效力、记忆权威、经验机制化 | manual:本仓 policy/ 仅收紧不放宽;记忆四层按条文执行(任务卡=任务记忆,documents/records=项目记忆,Dev 仓 AGENTS.md 指针已就位) |
|
||||
@@ -25,6 +26,7 @@
|
||||
| 原规则/章节 | 项目采用方式 | 原因与风险 | 负责人/复查条件 |
|
||||
|---|---|---|---|
|
||||
| baseline 硬边界 1(授权范围) | 高后果双钥匙:改写历史/解除分支保护/删归档/发布——Agent 只准备,用户执行(AGENTS.md 条文) | 单人+Agent 场景下消除单点;风险=用户不在场时高后果操作排队 | weichen;首次触发时复查 |
|
||||
| delivery.md §2、design-verification.md 的轻量流程默认做法 | 按 [policy/delivery.md](delivery.md) 默认逐阶段人工评审;小任务简化篇幅,阶段内可迭代;明确授权时在指定范围连续推进 | 保留需求、方案和实施决策权;按变化影响重审,避免每条命令审批及全流程重复返工 | weichen;阶段等待或试验边界影响交付时复查 |
|
||||
|
||||
- 历史记录(2026-09-30)报告 11 个组合仓 main 禁直推、拒绝陈旧候选;当前平台能力须独立重验,本地脚本测试不替代远端证据。
|
||||
- 当前规范内容以 gitlink 及其 VERSION 为准。治理可靠性修复的命令与证据约定见 [开发门禁](governance.md),本地与客户端/平台能力分别登记;本轮不改变分支保护、发布授权或通用库版本。
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
# 需求、试验与迭代交付
|
||||
|
||||
适用:本项目的需求、修复、规范修改和其他交付任务。依据固定版本的
|
||||
[通用交付流程](../deps/development-guidelines/workflows/delivery.md),本项目收紧为
|
||||
**默认逐阶段人工评审;阶段内迭代,按影响回退,按增量交付**。
|
||||
本文件是阶段与评审的权威表述;启动、同步、命令证据和回收操作见
|
||||
[开发门禁](governance.md)。规则的执行能力见 [能力矩阵](tool-adaptation-matrix.md)。
|
||||
|
||||
## 授权与阶段评审
|
||||
|
||||
任务卡默认记为 `manual`。完成当前阶段产物并取得人工评审结论后,才进入下一阶段。
|
||||
评审记录包含阶段、对象版本、评审人、时间、结论、意见及可追溯依据;结论使用
|
||||
未评审、通过、需修改、拒绝、不适用。人工结论与命令执行证据分开记录;Agent 自审、
|
||||
测试通过、工具写入或用户沉默均不能代替人工批准,也不能由作者代签独立审核。
|
||||
|
||||
只有用户明确要求自动或连续推进时,才将对应范围记为 `authorized-continuous`,记录
|
||||
授权来源、覆盖阶段、允许动作、交付终点、资源约束和停止条件。未覆盖阶段仍逐阶段评审。
|
||||
授权连续推进不免除需求分析、试验判定、测试、代码 Review、证据和平台准入;
|
||||
既有独立审核要求及高后果操作双钥匙仍有效。单独的合入授权不补齐尚不存在的前序产物。
|
||||
|
||||
阶段内已授权的调查、编辑、自检、缺陷修复和等价实现可以持续进行,无需逐命令批准。
|
||||
需求拆解、评估、需求表可以共用一份任务卡,但分别保留阶段结论。小任务缩短篇幅;
|
||||
确实不适用的内容说明原因,经人工确认或在明确授权的裁剪范围内处理,不能静默跳步。
|
||||
任务启动检查、独立工作区和收据用于准备现场,不表示任何阶段评审已通过。
|
||||
|
||||
## 阶段与出口
|
||||
|
||||
| 阶段 | 必需产物 | 进入下一阶段的条件 |
|
||||
|---|---|---|
|
||||
| 1 需求拆解 | 目标、用户场景、子需求、边界、非目标及待澄清问题 | 人工确认拆解与原始意图一致 |
|
||||
| 2 需求评估 | 价值、可行性、成本、风险、依赖、现有能力及在途任务重叠;与项目定位、模块职责和公开契约的符合度 | 人工确认取舍;重大未知转入下述受控试验 |
|
||||
| 3 需求表确认 | 稳定 ID、描述、适配依据、优先级、可判定验收条件、依赖和处理结论 | 人工确认本增量范围;影响实施的关键待核实项已处理 |
|
||||
| 4 方案设计 | 推荐方案与主要备选、职责和接口、数据与权限影响、失败恢复、待验证假设及试验结论 | 人工批准当前方案版本及剩余风险处理方式 |
|
||||
| 5 实施计划 | 关联需求的工作项、依赖顺序、责任人、文件或模块范围、测试方法与环境、完成条件及停止条件 | 人工批准当前实施和测试计划;远期工作可保留粗粒度 |
|
||||
| 6 实施与自检 | 可审查变更、局部测试、计划偏差与迭代记录 | 人工确认当前增量实现产物,必要设计调整已重新获批 |
|
||||
| 7 正式测试与验收 | 需求到证据映射;正常、异常、边界、回归结果及缺项 | 人工审阅当前候选的验证结果;正式验收前同步并固定被测对象 |
|
||||
| 8 代码 Review | 需求符合性、正确性、维护性、测试充分性及问题闭合记录 | 完成必要重放、整改、补测和复审,由有权评审者放行当前版本 |
|
||||
| 9 合入 | 最新 base/head、必要检查及评审、冲突处置、合入授权 | 合入前再次同步核验;经 PR 合入后取得真实合入结果 |
|
||||
| 10 合入核验与收口 | 实际合入内容及组件版本、验证依据、成果保存位置、写者状态、清理清单与任务归档安排 | 清理前取得人工批准或对应连续推进授权;安全回收后核对结果、闭合任务卡 |
|
||||
|
||||
表中的人工节点仅在明确的连续推进授权范围内按授权执行;阶段产物及验证条件保留。
|
||||
正式测试和最终 Review 的顺序不限制设计阶段试验、实施期测试或提前审阅。
|
||||
文本合并无冲突不证明组合兼容;合入后仍核验真实内容与被测候选是否一致。
|
||||
|
||||
## 需求表与追溯
|
||||
|
||||
需求表以任务卡为主记录。项目符合度使用“符合 / 需调整后符合 / 不符合 / 待核实”,
|
||||
附当前源码、项目约束或实测依据。处理结论使用“纳入本增量 / 后续处理 / 拒绝 / 待定”,
|
||||
与符合度分开;关键依据缺失时保留待核实,不凭推测判定通过。
|
||||
|
||||
每个纳入实施的需求必须能追溯到:
|
||||
|
||||
`需求 ID 与验收条件 → 方案及工作项 → 测试或审阅方法 → 当前版本结果与证据`。
|
||||
|
||||
没有可判定验收方法的需求先澄清;待定或不符合的需求未经重新评审不得进入正式实施。
|
||||
跨模块、权限、持久化、异步和恢复需求按实际风险补充真实链路及故障场景。
|
||||
规范和文档任务采用差异、链接、规则一致性及相关工具行为检查,不制造无关业务测试。
|
||||
|
||||
## 设计探索循环
|
||||
|
||||
需求分析和设计阶段允许先试验再完善方案,无须先批准尚未能确定的完整设计。
|
||||
执行试验前提交最小试验计划:待回答的问题或假设、对象和隔离环境、方法、预期判据、
|
||||
允许副作用、时间或成本边界、停止条件及产物保存或处置方式,并取得人工批准;
|
||||
已有连续推进授权明确覆盖该试验范围时,引用该授权。
|
||||
|
||||
在已批准范围内可以反复尝试:
|
||||
|
||||
`初步方案 → 批准试验范围 → 原型或测试 → 分析证据 → 修订方案与计划 → 结果评审`。
|
||||
|
||||
记录成功、失败及不确定结果,以及下一步继续探索、采用、换方案或暂停的理由。
|
||||
超出范围、触及未授权共享环境、达到预算或持续无有效进展时,暂停受影响试验并提交决策。
|
||||
无需强求全部未知一次消除;影响下一步的关键假设必须有结论,其余风险有责任人与处理安排。
|
||||
|
||||
原型标明用途和限制,不自动成为正式实现。决定复用时纳入方案、计划、代码 Review 与正式验证。
|
||||
试验成功仅证明相应假设,不能替代验收;失败结果用于调整方案,不能静默降低验收标准。
|
||||
|
||||
## 实施、测试与 Review 的反馈循环
|
||||
|
||||
按可独立验证的增量推进;近期工作细化到可执行,后续工作根据证据逐步细化。
|
||||
每轮形成“发现与证据 → 原假设或困难 → 调整及影响 → 重审和补测范围 → 决策 → 结果”。
|
||||
记录放在同一任务卡,较长材料只引用文件或 PR,避免多份状态。
|
||||
|
||||
| 变化 | 执行动作与评审边界 |
|
||||
|---|---|
|
||||
| 已批准范围内的内部组织、等价实现、局部缺陷修正 | 当前阶段继续调整、自测并记录;阶段出口统一人工评审 |
|
||||
| 技术路线、模块职责、公开契约、数据或权限设计、外部影响,或计划的关键依赖、交付顺序和资源约束变化 | 暂停受影响工作,修订方案或计划,经人工重审后继续;已有明确授权覆盖该类调整时按其边界执行 |
|
||||
| 目标、范围、优先级或验收条件变化 | 返回需求评估和需求表,取得对应批准后更新下游方案、计划和验证 |
|
||||
| 影响不明 | 先调查;仍无法判定时提交人工决定,不自行归入细节调整 |
|
||||
|
||||
未受影响且已有授权的工作可以继续。测试或 Review 发现实现缺陷,返回实施修复;
|
||||
发现设计缺陷返回方案;发现需求理解错误返回需求阶段。只重走受影响环节,并说明
|
||||
未重走部分为何仍有效。新版本不能沿用已受影响的批准、测试或 Review 结论。
|
||||
|
||||
批准对象使用文档修订或提交标识;正式验证固定源码、组件组合与相关配置。
|
||||
对 head/base、依赖、需求或契约变化重新判断证据及评审的有效性,按影响补测和复审。
|
||||
阶段状态、测试状态、代码审核状态及合入状态分别记录,不以一个“完成”互相替代。
|
||||
|
||||
## 合入、清理与恢复
|
||||
|
||||
合入与清理分别核对授权及条件。仅回收本任务登记工作区,按开发门禁核对当前权威目标、
|
||||
父子仓成果、未跟踪和 ignored 文件、独有提交与引用、活动 Git 操作以及所有写者退出。
|
||||
无法证明成果已保存时保留现场;本地删除与远端分支删除分别报告。
|
||||
|
||||
清理前保存任务主记录与证据。执行回收时将命令输出用 evidence 的 `RECEIPT` 模式保存到
|
||||
待删目录之外;回收后的结果写入后续闭合记录,不能向已删除的任务卡补写收据。
|
||||
任务卡须回填真实主 PR 和完成状态并归档;闭合 PR 的创建、合入均依当前授权执行。
|
||||
post-merge 默认只提示,不因 pull 或 merge 自动提交、推送或创建闭合 PR。
|
||||
|
||||
中断或交接时记录当前有效版本、批准范围、未决假设、最新试验结论、剩余事项及下一动作。
|
||||
恢复后核对现场和授权,从最早未满足的环节续办;不重做仍有效的工作,不省略失效环节。
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
本文件细化根 AGENTS.md 的启动、验证和回收规则。通用语义以固定的
|
||||
`deps/development-guidelines` 为准;门禁实现及回归用例随本仓版本管理。
|
||||
需求表、设计试验、迭代调整、阶段产物与人工评审按 [迭代交付](delivery.md) 执行。
|
||||
任务卡记录批准来源与对象版本;本地 evidence 仅记录命令,不能证明人工批准。
|
||||
|
||||
## 启动与恢复
|
||||
|
||||
@@ -64,6 +66,9 @@ Git 对含子模块的工作区需要显式删除选项时,只有全部现场
|
||||
owner 须先独立确认其保存与归属,工具不把缓存的远端引用当作唯一数据已经备份的证据。
|
||||
远端分支删除与本地回收分别报告,失败不能声明两者全部完成。
|
||||
回收后由所有者执行 `make task-close` 闭合卡片;回收命令不顺带改写共享主检出。
|
||||
post-merge 仅提示,不自动调用闭合。`make task-close` 会提交、推送并可能创建 PR,
|
||||
执行者先按迭代交付规则核对该动作的授权及所选任务,保留未授权的其他任务现场。
|
||||
回收命令使用待删目录之外的 `RECEIPT` 保存输出,清理结果由后续闭合记录引用。
|
||||
|
||||
## CI 凭据边界
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
| A5 回收 | 本地命令检查;写者退出由 owner 确认 | 登记根目录、锁/操作状态、父子仓与唯一文件、合入核验 | `tests/test_task.py` |
|
||||
| A6 秘密 | 本地脱敏及 CI 获取边界;权限与宿主隔离另验 | 命令/输出/摘要脱敏,凭据不持久写 Git 配置 | `tests/test_evidence.py`、`tests/test_ci_credentials.py` |
|
||||
| A7 证据 | 本地 SELF 收据;外部来源独立核验 | 首次捕获、完整脱敏输出/摘要、对象记录、原样导入 | `tests/test_evidence.py`;CI/审阅链接另核 |
|
||||
| A8 阶段评审与迭代 | manual;模板和提示不构成批准身份校验或全流程阻断 | policy/delivery.md;任务卡记录需求、方案/计划、评审与试验迭代;post-merge 默认仅提示 | `tests/test_task.py` 核对模板及钩子不自动写入;人工核对批准范围和版本 |
|
||||
|
||||
## 失败处理
|
||||
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
# 本地钩子(post-merge):pull/merge 落地后尝试闭合已合入任务卡;ff-only 也会触发。
|
||||
# precheck [cards] 报告欠账,所有者可用 make task-close 手动兜底。
|
||||
# 本地钩子(post-merge):pull/merge 落地后提示 owner 按授权闭合任务卡;ff-only 也会触发。
|
||||
# precheck [cards] 报告欠账;此钩子只提示,不执行闭合或其他写入。
|
||||
# 触发条件收紧到"主检出 + 集成分支 main"——任务 worktree 里 task-sync 的 merge 不触发,
|
||||
# 防止把卡片闭合混进任务分支现场。失败只警告,绝不阻断 pull。
|
||||
# 注意:task.sh close 在主检出会另建 feature/card-close-* 分支提交(集成分支不直推),
|
||||
# 结束后切回 main;PR 由所有者合入。
|
||||
# 防止把卡片闭合提示混进任务分支现场。
|
||||
common=$(git rev-parse --git-common-dir) && common=$(cd "$common" 2>/dev/null && pwd) || exit 0
|
||||
mainrepo=$(dirname "$common")
|
||||
[ "$mainrepo" = "$PWD" ] || exit 0
|
||||
[ "$(git rev-parse --abbrev-ref HEAD)" = "main" ] || exit 0
|
||||
[ -f "$mainrepo/scripts/task.sh" ] || exit 0
|
||||
bash "$mainrepo/scripts/task.sh" close \
|
||||
|| echo "[warn] post-merge 卡片自动闭合失败——在主检出手动运行 make task-close" >&2
|
||||
echo "[next] owner 按已有授权在主检出运行 make task-close 闭合已合入任务卡;未授权时先取得授权。"
|
||||
exit 0
|
||||
|
||||
+43
-1
@@ -99,7 +99,7 @@ cmd_precheck() {
|
||||
else
|
||||
echo "[facts] WARN policy/facts.md 不存在——外部事实登记表缺失(AGENTS.md 证据与验证门禁)"
|
||||
fi
|
||||
echo "[required-reading] core/baseline.md, workflows/delivery.md §1$([ "$dirty" -gt 0 ] && echo ", standards/collaboration.md(树脏=他人或未收尾现场,不得写入)")"
|
||||
echo "[required-reading] core/baseline.md, workflows/delivery.md §1$([ -f policy/delivery.md ] && echo ", policy/delivery.md")$([ "$dirty" -gt 0 ] && echo ", standards/collaboration.md(树脏=他人或未收尾现场,不得写入)")"
|
||||
echo "[R0] $(echo "$rmain" | cut -c1-10)(完整:$rmain)"
|
||||
if [ "$dirty" -gt 0 ] || [ "${sub_drift:-0}" -gt 0 ]; then
|
||||
echo "[verdict] SHARED_WORKSPACE_BUSY — 工作树不干净,不得写入;先收尾或经 owner 确认"
|
||||
@@ -178,11 +178,48 @@ cmd_start() {
|
||||
- 工作区:${wt}(worktree);分支:${name}
|
||||
${parent_note}
|
||||
- 授权与交付终点:<本次允许的动作与终点;未授权事项写明>
|
||||
- 交付模式:manual(逐阶段人工评审);明确授权后可记为 authorized-continuous
|
||||
- 自动推进授权:无;授权范围:无;授权来源:无;授权终点:无;停止条件:无(未授权)
|
||||
- 当前阶段:需求拆解;当前增量:I1(待定义)
|
||||
- 流程依据:仓库根目录 policy/delivery.md(归档后仍按仓库根目录定位)
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
<预期结果、受影响入口/模块/契约;明确不做什么。>
|
||||
|
||||
## 需求分析
|
||||
|
||||
| ID | 描述 | 项目符合度及依据 | 优先级 | 验收条件 | 依赖 | 结论 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| R1 | 待填写 | 待评估 | 待定 | 待定义 | 待确认 | 待评审 |
|
||||
|
||||
## 方案与计划
|
||||
|
||||
- 方案引用:待填写(含对象版本)
|
||||
- 实施计划引用:待填写(含增量与需求 ID)
|
||||
- 测试计划引用:待填写(含需求 ID 与验收条件)
|
||||
|
||||
## 阶段评审
|
||||
|
||||
| 阶段 | 对象版本 | 结论 | 评审人 | 时间 | 依据 |
|
||||
|---|---|---|---|---|---|
|
||||
| 需求拆解 | 待定 | 未评审 | — | — | — |
|
||||
| 需求评估 | 待定 | 未评审 | — | — | — |
|
||||
| 需求表确认 | 待定 | 未评审 | — | — | — |
|
||||
| 方案设计 | 待定 | 未评审 | — | — | — |
|
||||
| 实施计划 | 待定 | 未评审 | — | — | — |
|
||||
| 实施与自检 | 待定 | 未评审 | — | — | — |
|
||||
| 正式测试与验收 | 待定 | 未评审 | — | — | — |
|
||||
| 代码 Review | 待定 | 未评审 | — | — | — |
|
||||
| 合入 | 待定 | 未评审 | — | — | — |
|
||||
| 合入核验与收口 | 待定 | 未评审 | — | — | — |
|
||||
|
||||
## 探索试验与迭代
|
||||
|
||||
| 增量/试验 | 假设 | 范围 | 判断和停止条件 | 批准依据 | 结果 | 变更影响 | 需重审补测 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| 待定义 | — | — | — | 未批准 | NOT_RUN | 待评估 | 待评估 |
|
||||
|
||||
## 同步记录
|
||||
|
||||
| 节点 | sync_base_sha | tested_head_sha | checked_at |
|
||||
@@ -200,6 +237,11 @@ ${parent_note}
|
||||
- 结果:
|
||||
- 验证:<结论摘要 PASS/FAIL/SKIP/NOT_RUN 逐项;逐条证据由 make evidence 写入上方证据表>
|
||||
- 影响与剩余项:
|
||||
|
||||
## 合入与清理
|
||||
|
||||
- 合入记录:NOT_RUN(授权依据、PR、合入 SHA、验证来源)
|
||||
- 清理记录:NOT_RUN(授权依据、写者退出确认、worktree/分支/任务卡处置)
|
||||
EOF
|
||||
(cd "$wt" && IMPORT_RECEIPT="$PRECHECK_RECEIPT" bash "${SCRIPT_DIR}/evidence.sh")
|
||||
git -C "$wt" add .task
|
||||
|
||||
+101
-1
@@ -89,6 +89,18 @@ class TaskLifecycleTests(unittest.TestCase):
|
||||
self.assertNotEqual(result.returncode, 0, result.stdout)
|
||||
self.assertIn("SYNC_REQUIRED", result.stdout)
|
||||
|
||||
def test_precheck_routes_existing_project_delivery_policy(self):
|
||||
result = self.task(self.repo, "precheck")
|
||||
self.assertNotIn("policy/delivery.md", result.stdout)
|
||||
policy = self.repo / "policy/delivery.md"
|
||||
policy.parent.mkdir()
|
||||
policy.write_text("# Project delivery policy\n")
|
||||
self.git(self.repo, "add", "policy")
|
||||
self.git(self.repo, "commit", "-m", "Adopt project delivery policy")
|
||||
result = self.task(self.repo, "precheck")
|
||||
reading = next(line for line in result.stdout.splitlines() if line.startswith("[required-reading]"))
|
||||
self.assertIn("policy/delivery.md", reading)
|
||||
|
||||
def test_sync_materializes_updated_component(self):
|
||||
child = self.add_submodule()
|
||||
wt = self.worktree()
|
||||
@@ -586,11 +598,99 @@ class TaskLifecycleTests(unittest.TestCase):
|
||||
self.task(self.repo, "start", "feature/new", env=self.env | {"PRECHECK_RECEIPT": str(receipt)})
|
||||
wt = self.root / "repo-wt-feature-new"
|
||||
self.assertTrue((wt / ".task/feature-new.md").is_file())
|
||||
self.assertIn("make precheck", (wt / ".task/feature-new.md").read_text())
|
||||
card = (wt / ".task/feature-new.md").read_text()
|
||||
self.assertIn("make precheck", card)
|
||||
self.assertIn("交付模式:manual(逐阶段人工评审)", card)
|
||||
self.assertIn("authorized-continuous", card)
|
||||
self.assertIn("流程依据:仓库根目录 policy/delivery.md", card)
|
||||
for field in ("授权范围", "授权来源", "授权终点", "停止条件"):
|
||||
self.assertIn(f"{field}:无", card)
|
||||
for field in ("当前阶段", "当前增量", "方案引用", "实施计划引用", "测试计划引用"):
|
||||
self.assertIn(field + ":", card)
|
||||
self.assertIn("| ID | 描述 | 项目符合度及依据 | 优先级 | 验收条件 | 依赖 | 结论 |", card)
|
||||
reviews = card.split("## 阶段评审\n", 1)[1].split("\n## ", 1)[0]
|
||||
self.assertIn("| 阶段 | 对象版本 | 结论 | 评审人 | 时间 | 依据 |", reviews)
|
||||
for stage in ("需求拆解", "需求评估", "需求表确认", "方案设计", "实施计划", "实施与自检",
|
||||
"正式测试与验收", "代码 Review", "合入", "合入核验与收口"):
|
||||
row = next(line for line in reviews.splitlines() if line.startswith(f"| {stage} |"))
|
||||
self.assertEqual(row.split("|")[3].strip(), "未评审")
|
||||
self.assertNotIn("通过", reviews)
|
||||
self.assertIn("## 探索试验与迭代", card)
|
||||
for field in ("假设", "范围", "判断和停止条件", "批准依据", "结果", "变更影响", "需重审补测"):
|
||||
self.assertIn(field, card.split("## 探索试验与迭代\n", 1)[1].split("\n## ", 1)[0])
|
||||
self.assertIn("## 合入与清理", card)
|
||||
for field in ("合入记录", "清理记录"):
|
||||
self.assertIn(field + ":NOT_RUN", card)
|
||||
body = self.git(wt, "log", "-1", "--format=%B").stdout
|
||||
for field in ("Why:", "Evidence:", "Impact:", "Refs:"):
|
||||
self.assertIn(field, body)
|
||||
|
||||
def install_post_merge_hook(self):
|
||||
hook = self.repo / ".git/hooks/post-merge"
|
||||
shutil.copyfile(SOURCE / "scripts/hooks/post-merge", hook)
|
||||
hook.chmod(0o755)
|
||||
|
||||
def publish_merged_task(self):
|
||||
publisher = self.root / "publisher"
|
||||
self.git(self.root, "clone", str(self.remote), str(publisher))
|
||||
self.git(publisher, "switch", "-c", "feature/merged")
|
||||
card = publisher / ".task/feature-merged.md"
|
||||
card.parent.mkdir()
|
||||
card.write_text("# Merged task\n任务主记录:待回填;状态:进行中;owner:test\n"
|
||||
"- 工作区:fixture;分支:feature/merged\n")
|
||||
self.git(publisher, "add", ".task")
|
||||
self.git(publisher, "commit", "-m", "Record merged task")
|
||||
self.git(publisher, "switch", "main")
|
||||
self.git(publisher, "merge", "--no-ff", "feature/merged", "-m",
|
||||
"Merge pull request 'Task' (#7) from feature/merged into main")
|
||||
self.git(publisher, "push", "origin", "main")
|
||||
return self.git(publisher, "rev-parse", "HEAD").stdout.strip(), card.read_text()
|
||||
|
||||
def assert_post_merge_only_reminds_owner(self, operation):
|
||||
expected_head, expected_card = self.publish_merged_task()
|
||||
self.git(self.repo, "fetch", "origin")
|
||||
old_head = self.git(self.repo, "rev-parse", "HEAD").stdout.strip()
|
||||
local_heads = self.git(self.repo, "show-ref", "--heads").stdout
|
||||
worktrees = self.git(self.repo, "worktree", "list", "--porcelain").stdout
|
||||
remote_refs = self.git(self.remote, "show-ref").stdout
|
||||
self.install_post_merge_hook()
|
||||
result = self.git(self.repo, *operation)
|
||||
self.assertIn("make task-close", result.stdout)
|
||||
self.assertIn("授权", result.stdout)
|
||||
self.assertNotIn("[close]", result.stdout)
|
||||
self.assertEqual(self.git(self.repo, "branch", "--show-current").stdout.strip(), "main")
|
||||
self.assertEqual(self.git(self.repo, "rev-parse", "HEAD").stdout.strip(), expected_head)
|
||||
self.assertEqual(self.git(self.repo, "show-ref", "--heads").stdout,
|
||||
local_heads.replace(old_head, expected_head))
|
||||
self.assertEqual(self.git(self.repo, "worktree", "list", "--porcelain").stdout,
|
||||
worktrees.replace(old_head, expected_head))
|
||||
self.assertEqual(self.git(self.remote, "show-ref").stdout, remote_refs)
|
||||
self.assertEqual(self.git(self.repo, "status", "--porcelain").stdout, "")
|
||||
self.assertEqual((self.repo / ".task/feature-merged.md").read_text(), expected_card)
|
||||
self.assertFalse((self.repo / ".task/archive").exists())
|
||||
|
||||
def test_post_merge_main_merge_only_reminds_owner(self):
|
||||
self.assert_post_merge_only_reminds_owner(("merge", "--ff-only", "origin/main"))
|
||||
|
||||
def test_post_merge_main_pull_only_reminds_owner(self):
|
||||
self.assert_post_merge_only_reminds_owner(("pull", "--ff-only"))
|
||||
|
||||
def test_post_merge_is_silent_outside_main_checkout(self):
|
||||
wt = self.worktree()
|
||||
self.install_post_merge_hook()
|
||||
self.advance_remote()
|
||||
result = self.git(wt, "merge", "--ff-only", "origin/main")
|
||||
self.assertNotIn("make task-close", result.stdout)
|
||||
self.assertNotIn("[close]", result.stdout)
|
||||
self.git(self.repo, "switch", "-c", "feature/primary")
|
||||
self.git(wt, "switch", "-c", "feature/advance")
|
||||
(wt / "feature-work").write_text("another task\n")
|
||||
self.git(wt, "add", "feature-work")
|
||||
self.git(wt, "commit", "-m", "Advance feature")
|
||||
result = self.git(self.repo, "merge", "--ff-only", "feature/advance")
|
||||
self.assertNotIn("make task-close", result.stdout)
|
||||
self.assertNotIn("[close]", result.stdout)
|
||||
|
||||
def test_start_stacked_branch_records_parent_and_main_baseline(self):
|
||||
base = self.git(self.repo, "rev-parse", "origin/main").stdout.strip()
|
||||
parent = self.worktree("feature/parent")
|
||||
|
||||
Reference in New Issue
Block a user