diff --git a/.agents/skills/dev-flow/SKILL.md b/.agents/skills/dev-flow/SKILL.md index a852f92..ea61dee 100644 --- a/.agents/skills/dev-flow/SKILL.md +++ b/.agents/skills/dev-flow/SKILL.md @@ -61,6 +61,7 @@ dev-flow 编排已有能力,**不重复实现它们**: 1. **澄清** —— 用 `grill-with-docs` 的方法,但按上面的 **「冲突裁决」** 覆盖它的默认: 范围收窄(只问答案会改变产物的问题)、ADR 落点为 `decision.md`、`CONTEXT.md` 用 `devflow/glossary/` 下那份。 + **被否决的答案当场记进 `decision.md` 的 `## Alternatives considered`**(一行一条:问过什么、为什么输)——这是 Q&A 形态,见 `references/decision-note.md`)。 2. **读上下文**:`devflow/glossary/CONTEXT.md`,并搜索 `devflow/rejected/` 与已归档的 `decision.md`—— **避免重新提出已经被否决过的方案。** 3. 写 `openspec/changes//proposal.md`,并用 OpenSpec 补全 `design.md` / `specs/` / `tasks.md`。 @@ -73,6 +74,9 @@ dev-flow 编排已有能力,**不重复实现它们**: > 未获授权不得进入 Build。 > **方案讨论中的任何一次确认,都不等于实现授权。** +> 快节奏交付下可以预授权,但必须显式:Think 退出时在 `decision.md` 写下 +> ``。静默跳过不允许——旁路是有意识的选择,不是遗忘。 +> 授权状态以这行标记为准,恢复会话时读它,不靠对话记忆。 ## Build — 做出来 @@ -82,6 +86,7 @@ dev-flow 编排已有能力,**不重复实现它们**: - 按 `tasks.md` 的纵向切片实现,按 `specs/` 验收。 - **分步验证**:每完成一层再继续,不要一次写完再验。 +- **tasks/design 里提到"参考 XXX 实现"的,实现前先完整读它**——设计文档点名参考而实现时没看,是返工最常见的来源。 - **冲突先分类再处理**: | 分类 | 处理 | @@ -104,9 +109,8 @@ Build 结束**自动进入 Close**,中间不设确认点。 1. **补齐 `decision.md`**——把 `## Decision` 校准为**实际发布的做法**(现在时),补 `## Consequences` 和 `## Verification`。 2. **执行收尾检查**(见下)。 -3. 有新术语 → 更新 `devflow/glossary/CONTEXT.md`。 -4. 有被否决的提案 → 写入 `devflow/rejected//`。 -5. **⏸ 确认点 2** —— 汇报产物、验证情况、剩余风险,询问是否归档。 +3. 检查澄清阶段的新术语**已**沉淀进 `devflow/glossary/CONTEXT.md`(写入时机在术语确认的当场,见「冲突裁决」;这里只查漏)。 +4. 有被否决的提案 → 确认**已在否决发生时**写入 `devflow/rejected//`(这里只兜底检查)。 **退出**:`decision.md` 五节齐全;收尾检查通过;用户已被询问是否归档。 @@ -122,7 +126,7 @@ Build 结束**自动进入 Close**,中间不设确认点。 | **一个事实只有一个权威** | 见下表 | **"非平凡"的判据**:改变行为、架构、跨文件或跨包的契约、流程或工具、测试策略、磁盘/线缆/配置格式,或其他维护者可能重新考察的决策。 -**豁免**:纯机械或局部编辑。 +**豁免**:纯机械或局部编辑。**小修不值得触发本流程**——dev-flow 是显式触发的 opt-in 流程,轻的第一道防线是不进来;后来发现重要时,允许事后补录 `decision.md`(retrofit 已验证)。 ### 事实的唯一权威 @@ -153,8 +157,7 @@ Build 结束**自动进入 Close**,中间不设确认点。 纯机械改动可以豁免。**豁免必须显式,但可以廉价**——目的是让"跳过"变成有意识的选择,而不是静默遗忘。 -> **计划中的自动化**:`scripts/check-dev-flow.sh`,遵循仓库现有脚本约定(`scripts/*.sh`)。 -> 在它落盘之前,上面三步手动执行。 +> **已落地**:`scripts/check-dev-flow.sh ` 执行上述三项检查;`--index` 扫描归档派生 `devflow/index.md`(不手写);`--all` 检查全部活跃 change。 ## 目录 @@ -166,11 +169,12 @@ openspec/changes// devflow/ ├── glossary/CONTEXT.md ← 跨项目术语 -├── rejected// ← 未实施的提案 -└── index.md ← 由脚本扫描归档生成,不手写 +├── rejected// ← 未实施的提案(否决发生时写入,不是 Close 时) +└── index.md ← scripts/check-dev-flow.sh --index 派生,不手写 ``` `rejected/` 的保留条件:它**仍能防止一个诱人的、有意义的错误**。否则整体删除。 +**边界**:`decision.md` 的 Alternatives 记"变更内"的方案备选;`rejected/` 收"整个提案被否决"的方向。提案在确认点 1 被整个否决时,当场写入 `rejected/`——那时流程已终止,Close 不会执行。 ## 触发规则 @@ -179,6 +183,7 @@ devflow/ 不要因为任务涉及 OpenSpec、跨模块、架构决策或 devflow 目录就自动触发。 未被这样要求之前,按普通工程任务处理。 +**`decision.md` 义务只覆盖经本流程的非平凡变更**——不经 dev-flow 的普通工程任务没有这个义务。 ## 相关文档 diff --git a/.agents/skills/dev-flow/references/decision-note.md b/.agents/skills/dev-flow/references/decision-note.md index 5ae26bb..a0c1468 100644 --- a/.agents/skills/dev-flow/references/decision-note.md +++ b/.agents/skills/dev-flow/references/decision-note.md @@ -24,7 +24,8 @@ | 节 | 写下时机 | 原因 | |---|---|---| | `## Problem` | **Think** | 动机在需求刚澄清时最准确 | -| `## Alternatives considered` | **Think** | 备选是在方案讨论中被否决的,当时记最真实;事后补写会变成回忆录 | +| `## Alternatives considered` | **Think**,grill 问答当场 | 备选是在方案讨论中被否决的,当时记最真实;事后补写会变成回忆录 | +| `` | **Think 退出时**(仅预授权场景) | 授权状态的文件载体,恢复会话时以它为准 | | `## Decision` | Think 记意图,**Close 校准为事实** | 见下 | | `## Consequences` | **Close** | 代价要等实现完才知道 | | `## Verification` | **Close** | 验证要跑过才能写成可重跑的命令 | @@ -65,6 +66,19 @@ **要求**:每个**真实存在过**的备选一段,加粗开头,说明它**为什么输了**。 +**首选形态是压缩 Q&A——一行一条**。grill 问答中被否决的答案,就是备选;当场一行记下,转写成本接近零: + +```markdown +## Alternatives considered + +- Q: 上完整 BM25 schema? A: 不——先 sparse-lite + RRF,schema 重建是后续变更。 +- Q: 默认用 hybrid? A: 不——dense 默认,hybrid 显式 opt-in。 +``` + +(SuperBizAgent 实测:180 个档案文件里,段落式备选记录率为 0;唯一自然发生的高质量备选记录就是这个 Q&A 形态。) + +**值得写深时**(难以逆转的架构决策)才展开成段落,并要求写出推理链: + ```markdown **新增 year 字段到条目数据。** 冗余且需要同步维护——`date` 已是唯一来源, 派生成本为零,多一个字段就多一处会不一致的地方。 @@ -78,6 +92,7 @@ | 只列备选,不说为什么输 | 等于没写——读者无法判断它现在是否仍然输 | | 把"什么都不做"当默认备选 | 除非当时真的认真考虑过维持现状,否则它只是修辞 | | 备选写成一堆标签 | 没有推理链,未来无法复用 | +| **段落式凑字数** | Q&A 一行能说清的,不要为了"看起来正式"展开成三段 | **"什么都不做"什么时候是真的备选**:当维持现状确实是一个被权衡过的选项时(例如"暂不修复这个边界,先观察")。 @@ -146,7 +161,7 @@ | 方案 | 被拒原因 | |------|---------| -| YAML 全优先 | 字段名不一致(date vs created) | +| YAML 全优先 | 字段名不一致(date vs created) | | 目录名全优先 | 标题中的语义信息在下划线转空格后丢失 | ``` @@ -154,6 +169,20 @@ **注意它的形式**:两条备选,每条一句被拒理由,没有废话。**短不等于差。** +### 值得写深的备选(真实) + +SuperBizAgent 的 `phase1-infrastructure/decisions.md` ADR-001(Flyway): + +```markdown +### 后果 +- 表结构修改必须通过 SQL 迁移脚本 +- 开发环境首次启动需要执行 Flyway 迁移 +- 生产环境部署自动执行未执行的迁移脚本 +``` + +难以逆转的基础设施决策,后果写得具体到"改表必须走迁移脚本"——三个月后最需要读的就是这几行。 +**这是 Q&A 一行记不住的那种备选,值得整段。** + ### 应当补录备选(真实) `openspec/changes/add-year-filter/` 那次变更,实际发生过两条备选,但一条都没记: diff --git a/.agents/skills/dev-flow/references/phases.md b/.agents/skills/dev-flow/references/phases.md index 4235472..934c5df 100644 --- a/.agents/skills/dev-flow/references/phases.md +++ b/.agents/skills/dev-flow/references/phases.md @@ -16,7 +16,7 @@ > **relentless 是对问题质量的,不是对数量的。** > 只问**答案会改变** `proposal.md` / `specs/` / `tasks.md` 的问题;不会改变产物的疑问,自己判断即可。 -**先自己查证,再问用户。** 查证时格外看两处——它们专门用来避免重复劳动: +**先自己查证,再问用户。** 查证时格外看四处——前两处专门用来避免重复劳动: 1. 搜 `devflow/rejected/` —— 这个方案是不是已经被否决过? 2. 搜已归档的 `decision.md` —— 相关决策的历史理由是什么? @@ -44,10 +44,12 @@ openspec/specs/ ← 相关的既有能力规格 - 关键假设(没有验证、但方案依赖它的部分) - 主要风险 - **放弃的备选**(1–2 条,连同为什么) -- 请求实现授权 +- 请求实现授权(或记录 ``) **不要**复述 proposal、不要列产物清单、不要贴对齐表格。用户要的是判断依据,不是工作汇报。 +**pre-authorized 是显式旁路,不是默认。** 它适合用户已在对话中明确说"直接做"的快节奏场景。写它 = 承认确认点被有意识地跳过;不写而直接进 Build = 违规。授权状态的唯一载体是这行标记——恢复会话时以它为准。 + --- ## Build — 做出来 @@ -58,6 +60,12 @@ openspec/specs/ ← 相关的既有能力规格 第一个切片完成后,对照 `specs/` 检查一次:验收场景是否真的成立。**规格写得含糊会在这里第一次暴露。** +### 参考实现先读,再动手 + +`tasks.md` / `design.md` 点名"参考 XXX 实现"的,**实现前完整读它**。路径不明确时按类名/模式 Grep 定位。 +设计文档点名参考而实现时没看,是返工最常见的来源(SuperBizAgent 复盘:山东商客接口因此返工 4-5 次)。 +第一次在某区域写代码、或要用项目现有基础设施(MQ/统一请求结构/工具类)时,同此处理。 + ### 冲突三分法的判断细则 先分类,再动手。分类的错误比不分类更糟。 @@ -123,8 +131,9 @@ Think 阶段已经写下了 `## Problem` 和 `## Alternatives considered`。Clos |---|---| | 没有 `openspec/changes//` | Think 之前 | | 有 `proposal.md`,但 `decision.md` 缺 `## Problem` | Think 进行中 | -| 有 `proposal.md` 和 `decision.md`,但没有实现授权 | **确认点 1** | -| 有实现,但 `decision.md` 缺 `## Decision` / `## Consequences` / `## Verification` | Close 进行中 | +| 有 `proposal.md` 和 `decision.md`,但没有 `` 或已获授权,实现未完成 | Build 进行中 | +| 实现完成,`decision.md` 缺 `## Decision` / `## Consequences` / `## Verification` | Close 进行中 | | `decision.md` 五节齐全 | 收尾检查 + 确认点 2 | **恢复时不重新提问已经解决的问题。** 先读 `decision.md` 和 `proposal.md`——已经确认过的内容就在里面。 diff --git a/devflow/glossary/CONTEXT.md b/devflow/glossary/CONTEXT.md index ff8c738..f1e9669 100644 --- a/devflow/glossary/CONTEXT.md +++ b/devflow/glossary/CONTEXT.md @@ -16,7 +16,7 @@ ### 真理源 (Source of Truth) - **日期**和**短标识符 (slug)**:由目录名 `knowledge_YYYYMMDD_Slug/` 提取。 - **显示标题**、**tags**、**author**:由 YAML frontmatter 提取。 -详见 [ADR-001](./adr/0001-directory-name-as-truth-source.md)。 +详见 [decision.md](../../openspec/changes/knowledge-index-panel/decision.md)(原 ADR-001,2026-09-18 迁移)。 ### 短标识符 (Slug) 目录名中 `YYYYMMDD_` 之后的部分。用于脚本定位目录和构建文件路径。不用于显示(显示标题来自 YAML frontmatter 的 `title` 字段)。 diff --git a/devflow/index.md b/devflow/index.md index 633ca91..f9a71c6 100644 --- a/devflow/index.md +++ b/devflow/index.md @@ -1,14 +1,13 @@ -# Devflow Index +# devflow 索引 -`devflow/index.md` 是 Phase 0.5 的默认上下文入口。每个 `devflow/projects/YYYY-MM-DD-{slug}/` 默认维护一行,帮助代理先定位相关项目,再读取具体 brief、acceptance、ADR 或 compound knowledge。 +> 本文件由 scripts/check-dev-flow.sh --index 派生生成,**不要手写**。 +> 存储层是 openspec/archive/ 下的归档目录;此处只是浏览视图。 -| 日期 | slug | 领域 | 关键词 | 关联 OpenSpec | 状态 | -| --- | --- | --- | --- | --- | --- | -| 2026-05-18 | knowledge-index-panel | knowledge-index | knowledge-index, search, tags, static-html | `openspec/changes/knowledge-index-panel/` | active | -| 2026-05-19 | add-clear-filters | knowledge-index | clear-filters, search, tags, year-filter | `openspec/changes/archive/2026-05-19-add-clear-filters/` | archived | -| 2026-05-19 | add-year-filter | knowledge-index | year-filter, index-panel, frontmatter | `openspec/changes/add-year-filter/` | active | -| 2026-05-19 | dev-flow-skill-evaluation | sm-flow | dev-flow, sm-flow, skill-evaluation, fallback, phase-contracts | 未关联 | accepted-unarchived | -| 2026-05-21 | sm-flow-v3-1-upgrade | sm-flow | interface-impact, commit-gate, devflow-index, apply-conflict, skill-compatibility | `openspec/changes/archive/2026-05-21-sm-flow-v3-1-upgrade/` | archived | -| 2026-05-22 | sm-flow-execution-hardening | sm-flow | execution-hardening, checklist, phase-gate, cross-artifact, question-pool | 未关联 | active | -| 2026-07-05 | validate-sm-flow-explicit-trigger | sm-flow | explicit-trigger, scale-source, fallback, validation | `openspec/archive/2026-07-05-validate-sm-flow-explicit-trigger/` | archived | -| 2026-07-05 | validate-sm-flow-standard-change | sm-flow | standard-change, full-artifacts, evidence, validation | `openspec/archive/2026-07-05-validate-sm-flow-standard-change/` | archived | +| 日期 | 标题 | 归档位置 | +|---|---|---| +| 2026-05-25 | knowledge-index-sort Proposal | openspec/changes/archive/2026-05-25-knowledge-index-sort | +| 2026-09-18 | Decision: 建立旧 devflow 档案的迁移规则 | openspec/changes/archive/2026-09-18-migrate-devflow-archives | +| 2026-05-19 | 2026-05-19-add-clear-filters | openspec/archive/2026-05-19-add-clear-filters | +| 2026-05-21 | 2026-05-21-sm-flow-v3-1-upgrade | openspec/archive/2026-05-21-sm-flow-v3-1-upgrade | +| 2026-07-05 | Validate SM Flow Explicit Trigger | openspec/archive/2026-07-05-validate-sm-flow-explicit-trigger | +| 2026-07-05 | Validate SM Flow Standard Change | openspec/archive/2026-07-05-validate-sm-flow-standard-change | diff --git a/openspec/changes/add-year-filter/decision.md b/openspec/changes/add-year-filter/decision.md new file mode 100644 index 0000000..5655205 --- /dev/null +++ b/openspec/changes/add-year-filter/decision.md @@ -0,0 +1,70 @@ +# Decision: 年份筛选采用纯前端派生,不新增数据字段 + +## Problem + +知识索引只能按关键词和标签过滤。当条目跨越多个月份和年份时,列表只会越来越长,而用户缺少一个**粗粒度**的收敛手段——想回看某一年沉淀了什么,只能靠肉眼扫或者记住关键词。 + +而"年份"这个维度其实**已经躺在数据里**了:每个条目的 `date` 字段(格式 `YYYYMMDD`)是渲染日期时的唯一来源。也就是说这不是一个需要新增信息的需求,而是一个**已经存在的信息没有暴露给用户**的问题。 + +## Decision + +年份从 `ENTRIES[].date.slice(0,4)` 派生,**不新增数据字段**。 + +- 控件用原生 `` 代码引入依赖,与仓库"单文件静态 HTML、零依赖"的约束直接冲突。 + +**只修改生成后的 `knowledge-index.html`,不改生成脚本。** 更快,但 `knowledge-index.html` 是**生成产物**——下一次重建即丢功能,生成脚本才是真理源。这条在实现过程中确实被识别为"主要风险"(见 `design.md` 的架构审计一节),但**当时没有被记成一条备选**。它是一个真实的、有诱惑力的错误选项,所以补录在这里。 + +## Consequences + +**得到** + +- 零依赖、无数据迁移,没有新字段需要维护一致性。 +- 与既有搜索、标签过滤自然组合,因为三者走同一个 `applyFilters()` 入口。 +- 年份选项只列**实际存在**的年份,不会出现空年份。 +- 重建索引不会丢功能——修改落在生成脚本的模板里。 + +**代价** + +- **只有年粒度**:不支持月份、日期范围、时间线视图或自定义排序。 +- `