@zyaiting/keelson 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +101 -0
- package/README_CN.md +101 -0
- package/bin/keelson.js +15 -0
- package/hooks/codebuddy-session.mjs +67 -0
- package/hooks/opencode-session.mjs +65 -0
- package/hooks/prompt-state.mjs +66 -0
- package/hooks/session-start.mjs +94 -0
- package/package.json +64 -0
- package/registry/models.json +118 -0
- package/registry/platforms.json +92 -0
- package/skills/keelson/SKILL.md +44 -0
- package/skills/keelson/references/build.md +61 -0
- package/skills/keelson/references/context.md +34 -0
- package/skills/keelson/references/debug.md +46 -0
- package/skills/keelson/references/design-lenses.md +78 -0
- package/skills/keelson/references/discover.md +70 -0
- package/skills/keelson/references/engineer.md +110 -0
- package/skills/keelson/references/frontend-delivery.md +38 -0
- package/skills/keelson/references/frontend-interaction.md +31 -0
- package/skills/keelson/references/frontend-review.md +33 -0
- package/skills/keelson/references/frontend-visual.md +31 -0
- package/skills/keelson/references/frontend.md +33 -0
- package/skills/keelson/references/handoff.md +43 -0
- package/skills/keelson/references/harness.md +54 -0
- package/skills/keelson/references/interview.md +120 -0
- package/skills/keelson/references/land.md +47 -0
- package/skills/keelson/references/model.md +29 -0
- package/skills/keelson/references/plan.md +106 -0
- package/skills/keelson/references/reconcile.md +61 -0
- package/skills/keelson/references/shape.md +86 -0
- package/skills/keelson/references/verify.md +64 -0
- package/skills/keelson/templates/GLOSSARY.md +5 -0
- package/skills/keelson/templates/INTENT.md +22 -0
- package/skills/keelson/templates/NOW.md +9 -0
- package/skills/keelson/templates/README.md +60 -0
- package/skills/keelson/templates/ROADMAP.md +12 -0
- package/skills/keelson/templates/change-quick.md +16 -0
- package/skills/keelson/templates/change.md +32 -0
- package/skills/keelson/templates/delta-spec.md +12 -0
- package/skills/keelson/templates/handoff.md +27 -0
- package/skills/keelson/templates/ledger.md +3 -0
- package/skills/keelson/templates/resident-block.md +7 -0
- package/skills/keelson/templates/rules-general.md +10 -0
- package/skills/keelson/templates/rules-index.md +5 -0
- package/skills/keelson/templates/spec.md +14 -0
- package/skills/keelson/templates/tasks.md +9 -0
- package/skills/keelson/templates/workflow.md +18 -0
- package/skills/zh/keelson/SKILL.md +46 -0
- package/skills/zh/keelson/references/build.md +61 -0
- package/skills/zh/keelson/references/context.md +34 -0
- package/skills/zh/keelson/references/debug.md +46 -0
- package/skills/zh/keelson/references/design-lenses.md +78 -0
- package/skills/zh/keelson/references/discover.md +70 -0
- package/skills/zh/keelson/references/engineer.md +110 -0
- package/skills/zh/keelson/references/frontend-delivery.md +38 -0
- package/skills/zh/keelson/references/frontend-interaction.md +31 -0
- package/skills/zh/keelson/references/frontend-review.md +33 -0
- package/skills/zh/keelson/references/frontend-visual.md +31 -0
- package/skills/zh/keelson/references/frontend.md +33 -0
- package/skills/zh/keelson/references/handoff.md +43 -0
- package/skills/zh/keelson/references/harness.md +54 -0
- package/skills/zh/keelson/references/interview.md +120 -0
- package/skills/zh/keelson/references/land.md +47 -0
- package/skills/zh/keelson/references/model.md +29 -0
- package/skills/zh/keelson/references/plan.md +106 -0
- package/skills/zh/keelson/references/reconcile.md +61 -0
- package/skills/zh/keelson/references/shape.md +86 -0
- package/skills/zh/keelson/references/verify.md +64 -0
- package/skills/zh/keelson/templates/GLOSSARY.md +5 -0
- package/skills/zh/keelson/templates/INTENT.md +22 -0
- package/skills/zh/keelson/templates/NOW.md +9 -0
- package/skills/zh/keelson/templates/README.md +60 -0
- package/skills/zh/keelson/templates/ROADMAP.md +12 -0
- package/skills/zh/keelson/templates/change-quick.md +16 -0
- package/skills/zh/keelson/templates/change.md +32 -0
- package/skills/zh/keelson/templates/delta-spec.md +12 -0
- package/skills/zh/keelson/templates/handoff.md +27 -0
- package/skills/zh/keelson/templates/ledger.md +3 -0
- package/skills/zh/keelson/templates/resident-block.md +7 -0
- package/skills/zh/keelson/templates/rules-general.md +10 -0
- package/skills/zh/keelson/templates/rules-index.md +5 -0
- package/skills/zh/keelson/templates/spec.md +14 -0
- package/skills/zh/keelson/templates/tasks.md +9 -0
- package/skills/zh/keelson/templates/workflow.md +18 -0
- package/src/cli.js +87 -0
- package/src/commands/ablate.js +96 -0
- package/src/commands/ask.js +64 -0
- package/src/commands/attest.js +71 -0
- package/src/commands/check.js +127 -0
- package/src/commands/context.js +95 -0
- package/src/commands/design.js +63 -0
- package/src/commands/doctor.js +157 -0
- package/src/commands/focus.js +84 -0
- package/src/commands/guide.js +59 -0
- package/src/commands/handoff.js +41 -0
- package/src/commands/hook.js +23 -0
- package/src/commands/impact.js +58 -0
- package/src/commands/init.js +289 -0
- package/src/commands/land.js +258 -0
- package/src/commands/models.js +62 -0
- package/src/commands/new.js +70 -0
- package/src/commands/platforms.js +39 -0
- package/src/commands/retro.js +114 -0
- package/src/commands/status.js +115 -0
- package/src/commands/uninstall.js +30 -0
- package/src/commands/validate.js +117 -0
- package/src/lib/args.js +30 -0
- package/src/lib/changes.js +114 -0
- package/src/lib/check-activity.js +29 -0
- package/src/lib/config.js +102 -0
- package/src/lib/decisions.js +59 -0
- package/src/lib/evidence.js +127 -0
- package/src/lib/fs.js +126 -0
- package/src/lib/git.js +353 -0
- package/src/lib/glob.js +54 -0
- package/src/lib/health.js +113 -0
- package/src/lib/lifecycle.js +120 -0
- package/src/lib/maintenance.js +66 -0
- package/src/lib/markdown.js +438 -0
- package/src/lib/models.js +195 -0
- package/src/lib/out.js +13 -0
- package/src/lib/paths.js +82 -0
- package/src/lib/rules.js +27 -0
- package/src/lib/runtime-path.js +22 -0
- package/src/lib/session.js +100 -0
- package/src/lib/specs.js +345 -0
- package/src/lib/transaction.js +93 -0
- package/src/platforms/index.js +3 -0
- package/src/platforms/integration.js +384 -0
- package/src/platforms/registry.js +46 -0
- package/src/platforms/runtime.js +249 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# 前端设计
|
|
2
|
+
|
|
3
|
+
用于创建、改善、诊断或验收用户可见、可操作的界面。沿用现有变更生命周期,补充设计判断与可观察的界面验收。
|
|
4
|
+
|
|
5
|
+
## 按问题加载
|
|
6
|
+
<!-- keelson: id=frontend.routing | without: 局部修复被扩大为重设计,每次任务都加载全部指导 | sunset: never -->
|
|
7
|
+
|
|
8
|
+
先读取受影响页面、邻近页面、组件与 token。区分新建、延续现有系统、诊断和局部修复,只加载相关指导:
|
|
9
|
+
|
|
10
|
+
| 问题 | 指导 | 设计动作 |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| 诊断、优先级、验收 | `frontend-review.md` | audit、critique、polish |
|
|
13
|
+
| 层级、排版、配色、布局、图像、动效 | `frontend-visual.md` | typeset、color、layout、animate、simplify、bolder、quieter、delight |
|
|
14
|
+
| 表单、反馈、恢复、文案、首次使用、多语言 | `frontend-interaction.md` | harden、clarify、onboard |
|
|
15
|
+
| 设备、性能、复用系统、视觉迭代 | `frontend-delivery.md` | adapt、optimize、extract、document、explore、iterate |
|
|
16
|
+
|
|
17
|
+
`keelson design` 列出动作;`keelson design <action> [target]` 生成给宿主 Agent 的指导,不会执行审查、打开浏览器或编辑文件。自然语言请求按同样规则路由,用户不必记命令。只执行当前动作和原请求触发的章节;规划、审查与文档不隐含产品代码修改授权。浏览器检查适用于实际界面修改或视觉/交互结论;仅依据源码的文档应明确这一依据。build 先落实下面的真实任务,再按需加载视觉和交互指导。局部 bug 直接进入最窄修复与回归路径。
|
|
18
|
+
|
|
19
|
+
## 确定具体方向
|
|
20
|
+
<!-- keelson: id=frontend.direction | without: 装饰替代了清楚的任务与视觉主次 | sunset: never -->
|
|
21
|
+
|
|
22
|
+
根据请求和项目确定受众、主要任务、关键内容、使用条件与品牌约束。用一句话说明设计意图,例如“帮助频繁审核的用户优先看到异常,并在列表内处理”。复用已确认答案,只询问实质缺失的产品决策。
|
|
23
|
+
|
|
24
|
+
已有项目优先延续视觉系统,只有已观察到的问题需要时才调整。新界面根据内容选择连贯构图,不默认采用固定字体、渐变、卡片网格或巨大首屏。“更大胆”“更克制”“更高级”要转成强调、分组、密度或表达上的可观察改变。已有授权内的可逆设计由 Agent 判断。
|
|
25
|
+
|
|
26
|
+
长期产品事实进入已有 intent 或文档;稳定视觉约定仅在后续工作需要时写入现有设计文档或局部规则。单次页面不需要新增一套强制文档层级。
|
|
27
|
+
|
|
28
|
+
## 完成一条真实路径
|
|
29
|
+
<!-- keelson: id=frontend.slice | without: 首屏好看掩盖了状态缺失和控件不可用 | sunset: never -->
|
|
30
|
+
|
|
31
|
+
实施类任务先实现一条代表性用户路径,再扩展其他页面。使用真实或明确标注的代表性内容,包含长文本、缺失值与合理数据量。先解决任务阻塞和理解,再处理层级、响应式与装饰。可见控件必须有效、解释不可用状态,或在范围内移除。
|
|
32
|
+
|
|
33
|
+
将验收写进已有变更工件:谁,在什么状态和环境下,执行什么操作,看到什么结果,用什么检查证明。复用项目组件、工具和测试设施,不为展示复杂度增加依赖。完成前使用 `frontend-review.md` 与 `frontend-delivery.md` 的浏览器闭环;代码检查不能独自证明视觉质量。
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# 停下与继续
|
|
2
|
+
|
|
3
|
+
"做完了一个任务"和"推动了一个项目"的分界线,是下一个会话、下一个人、下一个模型能否不重做、不推翻地继续。两个文件承担这件事:项目级的 `NOW.md`,以及跨会话变更的 `changes/<name>/handoff.md`。
|
|
4
|
+
|
|
5
|
+
## 什么放在哪里
|
|
6
|
+
<!-- keelson: id=handoff.split | without: 会话日志要么当噪音提交进去,要么全部 gitignore,团队没有任何接续记录 | sunset: never -->
|
|
7
|
+
|
|
8
|
+
| 信息 | 存放位置 |
|
|
9
|
+
|---|---|
|
|
10
|
+
| 整个项目当前在做什么、什么受阻、下一步 | `NOW.md`,提交进 git,整份重写 |
|
|
11
|
+
| 单个变更的接续状态:已确认的决策、完成的切片、未决和受阻项、已排除的假设、下一步、验证状态 | `changes/<name>/handoff.md`,提交进 git |
|
|
12
|
+
| 已签名检查记录及引用的输出 | `changes/<name>/ledger.jsonl` + `evidence/`,随变更保留;分享前审阅输出 |
|
|
13
|
+
| 签名私钥、命令信任、会话草稿 | Git 私有的 `keelson-runtime` 目录,无 Git 时使用项目外用户缓存;永不提交 |
|
|
14
|
+
|
|
15
|
+
另一台机器上的同事需要的东西,都不是本地状态。
|
|
16
|
+
|
|
17
|
+
## 写交接
|
|
18
|
+
<!-- keelson: id=handoff.write | without: 下一个会话从翻 git 历史开始;被否决的假设被重试;未验证的工作被当成已验证 | sunset: never -->
|
|
19
|
+
|
|
20
|
+
运行 `keelson handoff <name>`(创建或重新盖戳 `handoff.md`,写入提交、时间和作者),填好六个段落。它是当前状态摘要:整份覆盖,绝不追加日记。
|
|
21
|
+
|
|
22
|
+
- **Goal and confirmed decisions** — 一段话,现在时,链接 `change.md` 而不是重复它。
|
|
23
|
+
- **Done** — 已完成且已验证的切片或任务,附证明它的 `Verify:`。
|
|
24
|
+
- **Open and blocked** — 每一项写明它阻塞什么。
|
|
25
|
+
- **Ruled out** — 已否决的假设或方案,附证据,免得有人重试。
|
|
26
|
+
- **Next step** — 第一个具体动作,小到能冷启动。
|
|
27
|
+
- **Verification** — 最后一条 `Verify:`(命令、退出码、tree)以及还没检查什么。
|
|
28
|
+
|
|
29
|
+
然后重写 `NOW.md`,让项目视图与之一致。下一个会话打开时,session-start hook 会打印交接里的下一步。
|
|
30
|
+
|
|
31
|
+
## 恢复
|
|
32
|
+
<!-- keelson: id=handoff.resume | without: 代理对着已经移动的工作树执行过期的交接,或者"清理掉"负责人想保留的未提交改动 | sunset: never -->
|
|
33
|
+
|
|
34
|
+
1. `keelson status`:工作、验证、发布状态,HEAD 是否自交接以来移动过,未提交的文件。
|
|
35
|
+
2. HEAD 移动过或工作树有改动,先读改了什么(`git log`、`git diff`)再信交接;可能有其他工作已落地,共享契约可能已变化。
|
|
36
|
+
3. 绝不为了"干净开始"删除或重置未提交的改动。要么问,要么绕开它们。
|
|
37
|
+
4. 在之前的验证上继续之前先重跑 `keelson check --record`;任何改动之后它按定义已过期。
|
|
38
|
+
5. 从 **Next step** 继续;再次停下时更新 `handoff.md` 和 `NOW.md`。
|
|
39
|
+
|
|
40
|
+
## NOW.md
|
|
41
|
+
<!-- keelson: id=handoff.now | without: 下一个会话两眼一抹黑,从 git 里重新推导状态 | sunset: never -->
|
|
42
|
+
|
|
43
|
+
整份重写,现在时,三个短段:正在进行什么(或"nothing in flight")、什么受阻或不确定(包括"尚未检查:……")、下一个具体步骤。`keelson land --now "<text>"` 在落地时替你写。暂停、受阻、取消都是正常状态;照实写,不要为了结束会话硬把变更说成"完成"。
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# 演进 Harness
|
|
2
|
+
|
|
3
|
+
一个有效的 Harness 做两件事:在 Agent 动手**之前**让正确路径更容易,在 Agent 动手**之后**给它足够便宜的信号来自我纠正。目标不是把模型写成脚本,而是把稳定的软件工程知识从聊天中搬到“能够可靠承载它的最小控制点”里。
|
|
4
|
+
|
|
5
|
+
## 约束不变量,不微操实现
|
|
6
|
+
<!-- keelson: id=harness.invariants | without: prose micromanages implementation details, goes stale with the code, and agents satisfy the recipe while violating the real boundary | sunset: never -->
|
|
7
|
+
|
|
8
|
+
写下长期必须成立的东西:依赖方向、API 兼容性、边界处的数据校验、验收条件、延迟预算。除非某个库、类结构或修改顺序本身就是契约,否则不要把它写死。
|
|
9
|
+
|
|
10
|
+
把不变量放到最窄的权威位置:
|
|
11
|
+
|
|
12
|
+
- 可观察的产品行为 → capability spec;
|
|
13
|
+
- 某些路径专属的工程约定 → `.keelson/rules/`;
|
|
14
|
+
- 可度量的不变量 → `config.yaml → check`,`kind: fitness`;
|
|
15
|
+
- 临时实现选择 → `change.md`,变更落地后删除。
|
|
16
|
+
|
|
17
|
+
好的机械检查只报告**哪个不变量在什么位置被破坏**,修复方式留给 Agent 判断。
|
|
18
|
+
|
|
19
|
+
## 把控制放在最便宜、最有用的位置
|
|
20
|
+
<!-- keelson: id=harness.control-loop | without: everything becomes always-on prose or a late CI surprise, wasting context before the edit and feedback time after it | sunset: never -->
|
|
21
|
+
|
|
22
|
+
| | 生成前(feedforward) | 生成后(feedback) |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| inferential | resident block、skill、scoped rules、specs | fresh-reader review、语义评审 |
|
|
25
|
+
| computational | codemod、typed API、generator | lint、typecheck、单元/集成测试、结构/fitness 检查 |
|
|
26
|
+
|
|
27
|
+
便宜且确定性的控制尽量靠近修改发生的位置:BUILD 回路里跑定向检查,宣布完成前跑配置好的完整检查,高成本/慢评审只在风险值得时使用。同一个规则不要同时复制到 resident、skill、rule 文件和 CI;选一个真相源,其余地方只指向它。
|
|
28
|
+
|
|
29
|
+
## 用“升级”处理重复错误,而不是不断长提示词
|
|
30
|
+
<!-- keelson: id=harness.promotion | without: recurring mistakes live as chat folklore, while every incident adds more prose and the always-on context grows without becoming more enforceable | sunset: when project-specific controls can no longer be traced to a live invariant or recurring failure -->
|
|
31
|
+
|
|
32
|
+
使用这条升级阶梯:
|
|
33
|
+
|
|
34
|
+
1. **第一次出现:** 修缺陷;如果问题走到了验证阶段,记录 root cause。
|
|
35
|
+
2. **同一类问题反复出现:** 运行 `keelson retro`,找出这些失败共同违反的稳定不变量。
|
|
36
|
+
3. **语义预防:** 在最窄的 spec/rule/reference 中补充或收紧规则,让 Agent 在编辑前更容易做对。
|
|
37
|
+
4. **确定性预防:** 如果脚本可以可靠发现违例,就做成 `fitness` check;如果足够快,再接入日常本地/CI 路径。
|
|
38
|
+
5. **自动化稳定后:** 删除或缩短只是重复检查内容的 prose。
|
|
39
|
+
|
|
40
|
+
不要把一次性的审美分歧自动化。只有错误会重复、代价明显、检测信号稳定时,才值得升级 Harness。
|
|
41
|
+
|
|
42
|
+
## 保留失败归因与回归证明能力
|
|
43
|
+
<!-- keelson: id=harness.attribution | without: the agent fixes failures that pre-date its change or records green checks that would also pass with the bug restored | sunset: never -->
|
|
44
|
+
|
|
45
|
+
高风险工作开始前,如果不先跑一次就无法判断失败是不是历史遗留,就建立有针对性的 baseline。实现过程中优先运行能定位当前切片的最小检查。修 bug 时保留负向回归证明:去掉修复后,新测试必须失败。宣布完成时,再针对你要声称的**同一棵工作树**运行新鲜的完整配置检查。
|
|
46
|
+
|
|
47
|
+
baseline 失败不等于可以忽略测试。把既有失败写清楚,不要扩大它,并独立验证你真正改到的表面,直到 baseline 能被单独修复。
|
|
48
|
+
|
|
49
|
+
## 让 Harness 可被删减
|
|
50
|
+
<!-- keelson: id=harness.adaptive | without: the repository accumulates workarounds for old model limitations and every future agent pays their context and process cost | sunset: when every non-permanent control has an explicit removal trigger and retro is run regularly -->
|
|
51
|
+
|
|
52
|
+
每条 Harness 规则都隐含一个假设:Agent 或项目在没有帮助时做不好某件事。这个假设需要被反复验证。优先保留绑定项目不变量的控制,而不是绑定某一个模型当前缺点的补丁。如果某条控制只是为了补偿观察到的 Agent 行为,就给它 sunset 条件,或至少给出继续保留它的可度量理由。
|
|
53
|
+
|
|
54
|
+
`keelson retro` 就是 Harness 的维护回路:根据 ledger 与失败证据去**新增、加强、放松或删除**指导。成熟的 Harness 应该越来越精准,而不是只会越来越大。
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# 自适应决策访谈
|
|
2
|
+
|
|
3
|
+
Keelson 的使用者不需要掌握软件架构术语。访谈是隐藏控制逻辑:只找出真正属于所有者的决定,让每个问题都容易回答,然后尽快回到实现。普通工作**不是**问卷;只有用户明确要求“深挖一下 / 压力测试这个方案”时,才深入走完同一棵决策树的重要分支。
|
|
4
|
+
|
|
5
|
+
## Question Protocol:每次打断都必须值得
|
|
6
|
+
<!-- keelson: id=interview.protocol | without: Agent 会问没必要的问题,把实现选型甩给用户,或者自己都说不清答案会改变什么 | sunset: never -->
|
|
7
|
+
|
|
8
|
+
提问前先在内部回答:
|
|
9
|
+
|
|
10
|
+
1. **后果** —— 这个答案会改变什么用户可见行为、验收边界、风险、成本、兼容承诺或长期决定?
|
|
11
|
+
2. **所有权** —— 答案属于仓库/现实、Agent 的工程判断,还是所有者的意图/风险偏好?
|
|
12
|
+
3. **可调查性** —— 代码、测试、文档、telemetry、官方文档或一个小实验能否回答?
|
|
13
|
+
4. **可逆性** —— 默认值猜错后,是局部低成本修正,还是昂贵/不可逆?
|
|
14
|
+
5. **信息价值** —— 它是不是最可能改变下一个安全切片的那个未决项?
|
|
15
|
+
6. **默认值** —— 如果用户说“你来决定”,你有依据的选择是什么?
|
|
16
|
+
|
|
17
|
+
如果说不清实质后果,或者答案根本不属于用户,就**不要问**。自行调查、采用可逆默认值,或留到后续切片。
|
|
18
|
+
|
|
19
|
+
## 第一个问题前先做盲点扫描
|
|
20
|
+
<!-- keelson: id=interview.blindspots | without: 访谈只能处理用户已经意识到的未知项,领域特有的失败模式仍会被漏掉 | sunset: never -->
|
|
21
|
+
|
|
22
|
+
开始访谈前做一次紧凑的风险触发扫描。只加载 `design-lenses.md` 中当前变更真正触发的行,先检查仓库和现有契约。重点寻找会改变设计的 unknown unknowns:破坏性数据语义、权限边界、外部兼容、重复/重试、迁移/回滚、故障恢复、可访问性、有测量依据的性能/成本,以及 AI 非确定性。
|
|
23
|
+
|
|
24
|
+
发现盲点**不等于**马上问用户。先路由成:已有保证、工程默认值、小实验、验收/证据场景,或者真正属于所有者的决定。只有最后一种才提问。
|
|
25
|
+
|
|
26
|
+
## 一次一个决定,优先“识别”而不是“回忆”
|
|
27
|
+
<!-- keelson: id=interview.one-at-a-time | without: 问题墙会压垮用户,而开放式技术术语会逼新人编造架构偏好 | sunset: never -->
|
|
28
|
+
|
|
29
|
+
提问前读取 `keelson ask list --json`,已确定的答案不得重复询问;新证据确实要求重开时使用 `ask reopen <id> --reason`。每轮至多提出三个独立、前提已满足的用户决定;依赖问题等待前提解决。用 `ask add`、`settle`、`assume`、`frontier` 保存归属、答案和依据,不可逆决定不能靠假设通过。优先用具体场景,并让用户“识别”而不是凭空“回忆”:
|
|
30
|
+
|
|
31
|
+
- 用用户自己的语言描述场景;
|
|
32
|
+
- 给 2–4 个**结果真正不同**的选项;有帮助时给每个选项附一条简短的 **工程影响**,不要让用户自己猜实现后果;
|
|
33
|
+
- 推荐一个默认值,并只说最重要的一条理由;
|
|
34
|
+
- 真有必要时只点出一个关键取舍;
|
|
35
|
+
- 合法时提供 **“不确定 / 采用你的推荐”**;
|
|
36
|
+
- 选项都不合适时允许自由回答。
|
|
37
|
+
|
|
38
|
+
差的问题:“Postgres 还是 MongoDB?”
|
|
39
|
+
|
|
40
|
+
更好的问题:“同一类记录是否允许不同用户自由增加不同字段,还是所有记录应遵循同一套字段结构?如果可变字段不是核心功能,我建议统一 schema,这样验证和迁移更简单。**工程影响:** 如果项目已经使用关系型数据库,直接沿用现有数据库建立固定字段表即可,不需要新增另一种数据库。”
|
|
41
|
+
|
|
42
|
+
不要要求用户记住前面几轮的上下文。问题里简短带上使它成立的事实或约束。
|
|
43
|
+
|
|
44
|
+
## 让问题一眼能看懂
|
|
45
|
+
<!-- keelson: id=interview.presentation | without: 正确的问题被埋在长段落里、推荐被误解成强制要求,或者用户无法快速看出各选项差别 | sunset: never -->
|
|
46
|
+
|
|
47
|
+
需要选项时,面向用户保持极简:
|
|
48
|
+
|
|
49
|
+
**需要决定:** <一个大白话问题>
|
|
50
|
+
|
|
51
|
+
- A. <可观察结果>
|
|
52
|
+
**工程影响:** <真正重要的数据模型 / 权限 / API / 运维后果>
|
|
53
|
+
- B. <可观察结果>
|
|
54
|
+
**工程影响:** <真正重要的实现后果>
|
|
55
|
+
- C. <只有真的不同才出现>
|
|
56
|
+
**工程影响:** <真正重要的实现后果>
|
|
57
|
+
- 不确定 —— 采用你的推荐
|
|
58
|
+
|
|
59
|
+
**推荐:** <选择>,因为 <一条决定性理由>。
|
|
60
|
+
**建议实现:** <优先复用现有技术栈;只有仓库证据支持或各选项确实不同,才写具体组件>。
|
|
61
|
+
|
|
62
|
+
只有“为什么现在必须决定”不明显时,才额外加一句说明。不要向用户暴露内部 lens 清单、评分过程或推理链。如果用户先要求解释,先在正常聊天里解释,再决定是否需要重问。
|
|
63
|
+
|
|
64
|
+
## 说明足够的实现后果
|
|
65
|
+
<!-- keelson: id=interview.implementation | without: 用户理解了产品选择,却不知道它在真实系统里意味着什么,或者 Agent 只堆技术名词却没有架构上下文 | sunset: never -->
|
|
66
|
+
|
|
67
|
+
写技术栈之前先检查仓库真实使用的技术。问题卡要把工程后果说具体,但不能变成“技术选购”:
|
|
68
|
+
|
|
69
|
+
- 现有技术栈能实现时,直接说明在现有栈里会改什么:schema/table、权限模型、endpoint/contract、background job、cache、migration 或测试面。
|
|
70
|
+
- **不需要新增技术时明确说不需要。** 不要为了显得专业就随便加 Redis、Kafka、新数据库、新 service 或新 framework。
|
|
71
|
+
- 不同选项真的对应不同架构时,才点名可能使用的具体技术/类别以及原因,例如“现有 Postgres + ACL 表足够”与“这个规模的团队广播需要 queue”。
|
|
72
|
+
- 绿地项目没有既定栈时,用**建议方向**而不是假装确定:“关系型数据库,例如 Postgres”“对象存储”“只有异步 fan-out 需要时才引入 queue”。
|
|
73
|
+
- 优先解释用户真正能理解的工程后果:一致性、迁移难度、运维成本、故障方式、权限边界和未来可逆性。
|
|
74
|
+
|
|
75
|
+
技术只是产品后果明确后的解释上下文,不能代替真正需要用户决定的问题。
|
|
76
|
+
|
|
77
|
+
## 按依赖顺序决定,并主动控制范围
|
|
78
|
+
<!-- keelson: id=interview.order | without: 产品边界还没确定就开始选技术,或者访谈一路扩张成尚未需要的未来架构 | sunset: never -->
|
|
79
|
+
|
|
80
|
+
大致按依赖顺序解决:
|
|
81
|
+
|
|
82
|
+
**问题/角色 → 范围与非目标 → 可观察行为 → 数据/权限不变量 → 外部契约 → 故障语义 → 昂贵架构 → 实现细节**
|
|
83
|
+
|
|
84
|
+
只有上游答案会改变后续分支时才问。发现 grab-bag 或 rabbit hole 时,把独立领域拆开,先确认哪个领域能解锁下一个真正有用的切片,把纯未来需求停放起来,不为“以后也许需要”提前设计。
|
|
85
|
+
|
|
86
|
+
某个实现细节即使存在多个合理方案,只要可逆,就不因为“有选择”而升级成用户问题。
|
|
87
|
+
|
|
88
|
+
## 适配表达,不给用户画像分级
|
|
89
|
+
<!-- keelson: id=interview.adaptive | without: 新人被迫猜术语,熟练用户收到冗长教程,项目还会持久保存脆弱的初级/高级标签 | sunset: never -->
|
|
90
|
+
|
|
91
|
+
所有人默认都先用场景和大白话。行为理解以后,确实有帮助时再用一句话补工程术语。所有者已经准确使用术语时直接沿用,并缩短解释。
|
|
92
|
+
|
|
93
|
+
永远不要让用户自选 beginner/intermediate/expert,也不要持久化这种标签。只根据当前对话自适应。 `guide: true` 增加的是教学:为什么重要、这个概念叫什么、什么时候该重审;它不增加 gate,也不增加强制问题数量。
|
|
94
|
+
|
|
95
|
+
## “我不知道”是有效答案
|
|
96
|
+
<!-- keelson: id=interview.uncertain | without: 用户被迫编造技术偏好、同一个问题反复出现,或本可由默认值/原型解决的选择阻塞整个工作 | sunset: never -->
|
|
97
|
+
|
|
98
|
+
把不确定当作路由信息:
|
|
99
|
+
|
|
100
|
+
- **现实拥有答案** → 自己调查。
|
|
101
|
+
- **可逆工程选择** → 沿用项目先例或采用推荐默认值。
|
|
102
|
+
- **属于用户但难以想象** → 给最小示例、payload、草图、对比或一次性原型。
|
|
103
|
+
- **性能/成本未知** → 先测量,再决定是否增加机制。
|
|
104
|
+
- **高影响且仍未知** → 只阻塞真正依赖它的切片。
|
|
105
|
+
- **用户先要求解释而不是回答** → 先在正常聊天里解释,不要立刻弹回同一张问题卡。
|
|
106
|
+
|
|
107
|
+
不要把“我不知道该选什么技术”变成技术投票;把它翻译成真正会影响技术选择的产品属性或运行约束。
|
|
108
|
+
|
|
109
|
+
## 回读结果、写回真相、及时停止
|
|
110
|
+
<!-- keelson: id=interview.stop | without: 答案只留在聊天里、同一个决定被重复询问,或者普通开发变成没完没了的访谈 | sunset: never -->
|
|
111
|
+
|
|
112
|
+
得到答案后,用一句话确认 **决定 + 后果**,只把长期有效的结果写入其所属工件,然后重新计算 decision frontier。不要保存访谈流水账。
|
|
113
|
+
|
|
114
|
+
普通工作中,只要下一个纵向切片已经具备:
|
|
115
|
+
- 清楚的可观察结果;
|
|
116
|
+
- 必要的边界/非目标;
|
|
117
|
+
- 没有真正阻塞它的 owner-owned 未决项;
|
|
118
|
+
- 明确的 acceptance / evidence 路径;
|
|
119
|
+
|
|
120
|
+
就停止提问。后续切片的问题可以保持 open,但不阻塞当前工作。只有用户明确要求 深挖 / 压力测试时,才继续走完请求边界内的**重要**分支;仍然拒绝纯未来假设和低价值实现细节。
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# 集成与发布
|
|
2
|
+
|
|
3
|
+
切片都验证通过,变更就是已实现;进入目标分支且 specs 已折叠,就是已集成;某个打了 tag 的版本把它发出去,才是已发布。这是三种状态,Keelson 分别报告。
|
|
4
|
+
|
|
5
|
+
## `keelson land <name>`
|
|
6
|
+
<!-- keelson: id=land.command | without: delta specs 永远不合并,specs 不再描述当前系统,未验证或未批准的工作被宣布为已集成 | sunset: never -->
|
|
7
|
+
|
|
8
|
+
变更已集成时运行(已合并,或在单人仓库里已提交到主线)。以下任一条成立它都拒绝,并说明是哪一条:
|
|
9
|
+
|
|
10
|
+
- 验收项未勾选(任务复选框只是计划状态,不是 landing gate);
|
|
11
|
+
- 还有未决问题;
|
|
12
|
+
- 验证是 not-run、failed、partial 或 stale(指纹与工作树不一致);
|
|
13
|
+
- 存在 `(assumed)` 决策而没有传 `--confirm-assumptions` — 确认它们的是负责人,不是你;
|
|
14
|
+
- delta 写好之后主 spec 变了而没有传 `--accept-drift` — 重读、对齐,再传该参数;
|
|
15
|
+
- 有 **BREAKING** 却没有 **Rollout** 段。
|
|
16
|
+
|
|
17
|
+
然后它把每个 delta 合并进对应能力的 spec(ADDED 追加,MODIFIED 按名替换,REMOVED 删除),追加 `Decisions` 行,删除 change 目录(`land: fold`,默认)或归档它(`land: keep`)。`--dry-run` 预览全部动作。`--force` 只用于负责人的明确决定,不是为了省事。
|
|
18
|
+
|
|
19
|
+
把落地和最后一次代码改动一起提交,让 specs 和满足它们的代码处在同一个版本。ledger 和 handoff 留在 git 历史里;`keelson retro` 从那里读取。
|
|
20
|
+
|
|
21
|
+
## 代码和 specs 一起评审
|
|
22
|
+
<!-- keelson: id=land.same-pr | without: 文档在里程碑结束时才"补齐",那时已经没人记得为什么 | sunset: never -->
|
|
23
|
+
|
|
24
|
+
改变行为的 pull request 带着 delta spec 和决策行。只看 diff 不看 spec 的评审者,分不清一处行为变化是不是有意的。
|
|
25
|
+
|
|
26
|
+
## 相撞
|
|
27
|
+
<!-- keelson: id=land.collisions | without: 另一个变更已经把契约从底下挪走了,旧的决策或验证还被当成有效 | sunset: never -->
|
|
28
|
+
|
|
29
|
+
另一个变更修改了共享契约、目标分支或验证环境时,旧变更的决策和证据可能不再成立。信号:`keelson status` 的共享契约警告、`land` 的漂移拒绝、合并之后的过期验证。应对:重读被挪动的 spec,对齐 delta,重跑 `keelson check --record`,然后才落地。spec 合并先预览,绝不静默覆盖。
|
|
30
|
+
|
|
31
|
+
## 发布状态
|
|
32
|
+
<!-- keelson: id=land.release | without: "已合并"被报成"已上线",迁移或人工步骤被忘掉 | sunset: never -->
|
|
33
|
+
|
|
34
|
+
发布状态由 git tag 推导:`keelson status` 把最近一个 tag 之后落地的变更列为未发布。带 **Rollout** 段的变更,在它的步骤跑完之前不算完成;在那之前把它们留在 `NOW.md → Next`。Keelson 可以提醒;它自己绝不执行生产操作。
|
|
35
|
+
|
|
36
|
+
## 归档之前先回写
|
|
37
|
+
|
|
38
|
+
落地合并的是 delta 和决策。变更教给你的其余东西(一个新术语、一项移动了的职责、一个质量数字、一条可以变成检查的约束、一个值得回归测试的缺陷)由 `references/reconcile.md` 负责分派去向。在 `keelson land` 之前做完这一遍,让真相文件和代码共享同一个落地提交。
|
|
39
|
+
|
|
40
|
+
## 沉淀经验,登记技术债
|
|
41
|
+
<!-- keelson: id=land.promote | without: 同一条约定在每个变更里被重新发现;晚发现的缺陷变成传说而不是检查 | sunset: never -->
|
|
42
|
+
|
|
43
|
+
收尾前用一行话问自己:这次变更有没有暴露出值得写成 rule 的约定、值得加进 `config.yaml → check` 的检查、值得写成需求的契约、值得写成回归测试的缺陷?优先顺序:自动化检查、spec 需求、带范围的 rule,然后才是决策行。停留在一段散文里的问题会被重新学一遍。已知的遗留问题变成有负责人的跟踪项(在任务系统里,或 `ROADMAP.md → Next`),而不是总结里的一句话。
|
|
44
|
+
|
|
45
|
+
## Spec `Decisions` 的写法
|
|
46
|
+
|
|
47
|
+
一条决策行一到三行,现在时,写明被否决的选项:`- messaging: consumers are idempotent; exactly-once delivery rejected because the broker does not provide it`。决策后来反转时,重写这一行并在末尾留一句:`(previously: at-most-once, abandoned after duplicate-notification incident)`。绝不让 `Decisions` 变成 changelog。代码与已确认的需求不一致时,报告差距;改 spec 去迁就缺陷需要负责人的决定。
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# 领域模型与共同语言
|
|
2
|
+
|
|
3
|
+
活得久的项目会积累词汇:同一个词开始有两个意思,两个词开始指同一件事。模型层维护的是词汇、系统各部分之间的边界,以及每个部分内部必须成立的不变量。
|
|
4
|
+
|
|
5
|
+
## 一个词,一个意思
|
|
6
|
+
<!-- keelson: id=model.language | without: "account"、"user"、"member"、"profile" 在代码、specs 和对话里各自漂移,每次变更都从一场翻译争论开始 | sunset: never -->
|
|
7
|
+
|
|
8
|
+
出现在 specs、代码标识符和对话中的术语,放在 `.keelson/GLOSSARY.md` 里,一行一个:`- Member — 一个 User 在某个 Workspace 内的身份;携带角色`。当请求用到不在表里的术语,或者把术语表里的词用成了别的意思,先厘清再设计。当一个术语在系统的不同部分确实意味着不同的东西时,点明是哪个部分,两行都保留;这条边界就是一个 bounded context,两个部分通过显式翻译来交流,而不是共用一张表。
|
|
9
|
+
|
|
10
|
+
specs、rules 和 change.md 使用术语表里的词。代码在命名上跟随它;代码已经用了另一个词时,变更要么改名,要么把映射记在那条术语表条目里。
|
|
11
|
+
|
|
12
|
+
## 边界与不变量
|
|
13
|
+
<!-- keelson: id=model.boundaries | without: 模块彼此知道得太多;一处改动泄漏到三处,spec 说不清谁对什么负责 | sunset: never -->
|
|
14
|
+
|
|
15
|
+
每个能力的 spec 回答两件事:"这部分向系统其余部分承诺了什么"(需求)和"它内部什么永远不能为假"(不变量:订单总额等于明细之和;被撤销的链接在每条路径上都返回 404)。当变更跨越边界时,delta 点名发生变化的契约,另一侧的负责人会在 `keelson status` 里看到它是一个共享契约。
|
|
16
|
+
|
|
17
|
+
对于不属于行为的架构约束("媒体流水线绝不写权限表"、"每次读取都经过 `canView()`"),用一条限定在它所管辖路径上的 rule,并尽可能在 `config.yaml → check` 里加一个被违反时会失败的检查。只活在散文里的约束,会被某个从没读过它的人打破。
|
|
18
|
+
|
|
19
|
+
## 隐藏会变的东西
|
|
20
|
+
<!-- keelson: id=model.deep-modules | without: 接口照搬当前实现;每次内部改动都变成接口改动,波及所有调用方 | sunset: never -->
|
|
21
|
+
|
|
22
|
+
设计模块或接口时,问:调用方需要知道什么?哪些复杂性可以留在接口后面?什么最可能变?这些知识是否已经泄漏到了其他模块?宁要一个小接口配一个深实现,也不要一堆暴露内部的薄模块。衡量标准不是文件长度,而是调用方必须理解的事情有多少。
|
|
23
|
+
|
|
24
|
+
当一个能力的 spec 不断增长、需求之间不再共享同一个目的时,这是新建一个带自己 spec 的能力的信号,而不是把文件写得更长。
|
|
25
|
+
|
|
26
|
+
## 设计两次,但要便宜
|
|
27
|
+
<!-- keelson: id=model.design-twice | without: 第一个想到的设计就被实现,它的代价要到代码评审时才被发现 | sunset: never -->
|
|
28
|
+
|
|
29
|
+
对于 spec 变更,选定之前先在 `## Alternatives` 下各用几行勾勒两个设计:各自暴露什么接口、各自隐藏什么、各自让什么在以后变难。第二个草图往往更差;写它的过程,正是你弄清第一个草图付出了什么代价的方式。把被否决的那个连同它最强的论据一起记下来。
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Planning(规划)
|
|
2
|
+
|
|
3
|
+
`keelson new <name> --tier quick|spec [--capability a,b] [--touches globs] [--depends other]` 搭好 change 目录,并记录负责人、分支和每个 delta spec 的基线。工件由你填写。计划的存在,是为了让工作跨过会话边界、让评审者能单独否决一个切片;它不是脚本。
|
|
4
|
+
|
|
5
|
+
## 一个变更处在哪里
|
|
6
|
+
<!-- keelson: id=plan.hierarchy | without: 要么每个任务都从零重新规划,要么写出一份三个月的逐文件计划,到第二周就错了 | sunset: never -->
|
|
7
|
+
|
|
8
|
+
项目目标(`INTENT.md`)→ 当前里程碑(`ROADMAP.md → Now`,或任务系统)→ 边界清楚的变更(`changes/<name>`)→ 可独立验收的切片(`tasks.md`)。只有后两者是 Keelson 创建的文件。近期工作写具体;后面的工作只写方向和依赖,放在 `ROADMAP.md → Next`。不要把还没探索的问题编成带虚构步骤的任务。
|
|
9
|
+
|
|
10
|
+
如果项目有任务系统(`config.yaml → refs.tasks`),它仍是"要做什么、按什么顺序"的权威。`change.md` 链接对应 issue,只保存任务系统没有的东西:决策、验收映射和接续状态。
|
|
11
|
+
|
|
12
|
+
## change.md
|
|
13
|
+
<!-- keelson: id=plan.change-md | without: 变更的理由和被否决的备选只存在于聊天里,然后丢失 | sunset: never -->
|
|
14
|
+
|
|
15
|
+
各段按顺序如下。quick 变更只需要 **Why**、**What** 和 **Acceptance**。
|
|
16
|
+
|
|
17
|
+
- **Why** — 用 1 到 3 句话写问题或机会。去掉方案也应能独立成立。
|
|
18
|
+
- **What** — 变更的要点列表。以 **BREAKING** 开头的条目标记破坏性变更;它需要一个 **Rollout** 段(兼容窗口、迁移、回滚),`keelson land` 会检查。
|
|
19
|
+
- **How** — 技术方案,写评审者想知道的部分。不是任务清单。
|
|
20
|
+
- **Alternatives** — 只有真正存在重要分叉时才写。记录最强的真实备选以及它为什么输。如果项目已有清晰惯例、根本没有真实分叉,就写 `follows <existing pattern>` 并指出依据,不要为了模板硬造两个选项。
|
|
21
|
+
- **Impact** — 你靠阅读发现的,而不是 diff 的文件列表。见 `context.md`。
|
|
22
|
+
- **Acceptance** — 每条验收标准一个复选框,各自写明怎么检查:`— test: name`、`— check: \`cmd\``、`— manual: how` 或 `— review: what`。这是从请求到证据的映射。`design-lenses.md` 触发且真正影响正确性的风险,要变成 acceptance/evidence 场景,而不是多写一篇散文。
|
|
23
|
+
- **Open questions** — `- question — blocks: <slice>`。还有未决问题时落地会被拒绝;什么都不阻塞的问题是备注,不是未决问题。
|
|
24
|
+
- **Rollout** — 仅用于破坏性变更、迁移或生产步骤。
|
|
25
|
+
- **Decisions** — 只保存 capability 局部的当前理由,并用现在时表达。工作假设写成 `- (assumed) capability: …`。跨领域、出人意料或昂贵且难撤销的架构决定,如果项目配置了 `refs.decisions`,应进入 ADR;ADR 保持短小且不可改写,后续变化用 supersede。
|
|
26
|
+
|
|
27
|
+
## 把审计结果路由到已有工件
|
|
28
|
+
<!-- keelson: id=plan.assumption-routing | without: clarification creates a new diary document, or critical assumptions stay only in chat and disappear across sessions | sunset: never -->
|
|
29
|
+
|
|
30
|
+
假设审计只是对话中的临时工作区,不再新建一份永久文档。只有会影响未来工作的内容才沉淀:
|
|
31
|
+
|
|
32
|
+
- 明确的结果或非目标 → `change.md → What`;
|
|
33
|
+
- 为了继续工作而采用的工作假设 → `change.md → Decisions`,标为 `(assumed)`;
|
|
34
|
+
- 仍未回答、由用户掌握且会阻塞工作的缺口 → `change.md → Open questions`,写清阻塞什么;
|
|
35
|
+
- 已确认的可观察行为 → `Acceptance`;spec 档的行为还要写进 delta spec;
|
|
36
|
+
- 过程中发现的稳定术语或工程不变量 → `GLOSSARY.md`、窄范围 rule 或 fitness check。
|
|
37
|
+
|
|
38
|
+
变更落地以后,临时盘问过程随着 change 脚手架消失;留下来的只有当前行为、长期决策、规则、词汇和带证据的检查。
|
|
39
|
+
|
|
40
|
+
## Delta specs(spec 档)
|
|
41
|
+
<!-- keelson: id=plan.delta | without: 没人重写整份 spec,行为契约就渐渐偏离代码 | sunset: never -->
|
|
42
|
+
|
|
43
|
+
每个受影响的能力一个文件,位于 `changes/<name>/specs/<capability>/spec.md`,能力路径与主 specs 相同。`keelson new --capability` 创建它时带 `base:` 戳;如果主 spec 在你写的过程中变了,落地时会要求你先重读再传 `--accept-drift`。只写差量:
|
|
44
|
+
|
|
45
|
+
```markdown
|
|
46
|
+
## ADDED Requirements
|
|
47
|
+
### Requirement: Page size limit
|
|
48
|
+
The API SHALL reject `size` above 200 with HTTP 400.
|
|
49
|
+
#### Scenario: Oversized page
|
|
50
|
+
- WHEN a client requests `size=500`
|
|
51
|
+
- THEN the response is 400 with code `size_too_large`
|
|
52
|
+
|
|
53
|
+
## MODIFIED Requirements
|
|
54
|
+
### Requirement: Order listing
|
|
55
|
+
(full replacement text of the requirement)
|
|
56
|
+
|
|
57
|
+
## REMOVED Requirements
|
|
58
|
+
### Requirement: Legacy CSV export
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
一个 capability 在逻辑上仍是一份行为契约,但物理上不必永远只有一个文件。当合并后的契约超过配置的 spec 预算时,`keelson land` 会自动把它改写成小型 `spec.md` 索引 + `requirements/*.md` + 按需 `decisions/*.md`;后续 delta 仍把该 capability 当成一份逻辑 spec,base hash 也覆盖整份逻辑契约。不要手工重新合并 shards。
|
|
62
|
+
|
|
63
|
+
spec 是行为契约:可观察行为、输入、输出、错误条件、外部约束。如果实现改变而客户端看到的不变,它就不属于这里。架构不变量放在 `rules/` 或可执行 check;跨领域架构历史在项目有 `refs.decisions` 时进入 ADR;capability 局部的当前理由可以留在 decision shards。相同解释只链接,不重复。
|
|
64
|
+
|
|
65
|
+
## tasks.md 与切片
|
|
66
|
+
<!-- keelson: id=plan.tasks | without: 工作凭记忆执行;进度、切片和 effort 路由在会话之间不可见 | sunset: never -->
|
|
67
|
+
|
|
68
|
+
`tasks.md` 是**可变的执行计划**,不是第二份验收契约。复选框用来跨会话传递进度并辅助 effort 路由,但 `ready` 与 `land` 只由 acceptance、阻塞问题/假设、rollout/兼容性和新鲜 verification 决定。如果实现走出更好的路径,应更新或删除过时任务,而不是为了满足旧计划一直让生命周期保持未完成。
|
|
69
|
+
|
|
70
|
+
把任务分组放在 `## Slice: <name>` 下,配一行 `Delivers:` 说明切片完成后别人能观察到什么。quick 变更通常只有一个切片,可以省略标题。每个任务带一个 effort 层级,尽可能带一条验证命令:
|
|
71
|
+
|
|
72
|
+
```markdown
|
|
73
|
+
## Slice: Create and access
|
|
74
|
+
Delivers: a link can be created and opens the shared item
|
|
75
|
+
- [ ] 1. Add `POST /shares` (effort: standard) — verify: `npm test -- shares.create`
|
|
76
|
+
- [ ] 2. Render the share page (effort: light) — verify: `npm test -- shares.page`
|
|
77
|
+
|
|
78
|
+
## Slice: Revoke and expiry
|
|
79
|
+
Delivers: every access path refuses a revoked or expired link
|
|
80
|
+
- [ ] 3. Decide expiry semantics and update `specs/sharing` (effort: deep)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
粒度:任务是评审者可以单独否决的最小单位。评审者可能接受一半、否决另一半时就拆开。切片是负责人可以单独验收的最小单位。
|
|
84
|
+
|
|
85
|
+
### 切片是纵向的
|
|
86
|
+
<!-- keelson: id=plan.tracer-bullet | without: 先把 schema 做完、再把后端做完、再把前端做完,任何东西都还没端到端跑过,层与层之间的不匹配最后才被发现 | sunset: never -->
|
|
87
|
+
|
|
88
|
+
一个切片是一个真实的用户动作,穿过它触及的每一层(界面、API、领域、存储、响应、测试),薄但完整,然后才开始下一个动作。一个功能的第一个切片,是能证明各层能对得上的最窄路径:以"创建 issue"为例,就是表单、端点、校验、领域对象、数据行、响应、渲染结果,加一个测试。更新、删除、评论都在它跑通之后。`keelson validate` 会在切片按层命名("database"、"backend"、"UI")时给出警告。纵向切片内部有一个按层划分的任务没问题;按层划分的切片不行。
|
|
89
|
+
|
|
90
|
+
### Effort 层级
|
|
91
|
+
<!-- keelson: id=plan.effort | without: 每个任务都跑在最贵的模型上,或者最便宜的模型在做设计决策 | sunset: 当 retro 显示 light 层级在 100 次分派中一次通过率超过 90% 时,放宽 light 的标准 -->
|
|
92
|
+
|
|
93
|
+
- **light** — 机械、边界清楚、验证就是一条命令:照既有模式做、改配置、重命名、跑测试并汇报、格式化。
|
|
94
|
+
- **standard** — 需要上下文但路径清楚:大多数功能代码、普通 bug 修复、逐任务评审。
|
|
95
|
+
- **deep** — 歧义、跨层影响、设计取舍、安全、根因不明:起草 change.md 和 delta specs、架构裁定、疑难调试、最后的陌生读者评审。
|
|
96
|
+
|
|
97
|
+
`config.yaml → effort` 的下限:评审者不低于 `standard`;规划、最终验证和任何裁定不低于 `deep`。评审者的层级永远不低于它评审的实施者。
|
|
98
|
+
|
|
99
|
+
## 需求中途变化时
|
|
100
|
+
<!-- keelson: id=plan.requirement-change | without: 聊天里的一句"好的"是唯一记录;计划、验收和决策仍然描述旧需求 | sunset: never -->
|
|
101
|
+
|
|
102
|
+
负责人改主意的同一轮里,更新 `change.md`(What、Acceptance、Decisions)、delta spec 和受影响的切片。如果它已经变成另一个变更,用 `keelson cancel` 带理由取消旧的,重新开始。
|
|
103
|
+
|
|
104
|
+
## ledger.md
|
|
105
|
+
|
|
106
|
+
以一行标题开头。其余内容在构建和验证过程中追加。条目是 `###` 标题:`Ruling:`、`Root cause:`、`Verify:`、`Dispatch:`、`Escalate:`、`Note:`。`keelson check --record` 会替你写 `Verify:` 条目,并附上让过期可被检测的工作树指纹。
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# 回写与压缩
|
|
2
|
+
|
|
3
|
+
落地一个变更并不是它的终点。两道工序让项目知识保持真实且精简:回写把新的稳定事实写回当前真相,压缩把不再属于那里的东西移走。它们都是 RECONCILE 中 Agent 的内部职责,不是所有者需要主动请求的 housekeeping;`keelson doctor` 只保留为诊断视图。
|
|
4
|
+
|
|
5
|
+
## 回写:每个新事实去哪里?
|
|
6
|
+
<!-- keelson: id=reconcile.route | without: 变更产生的事实留在 change.md 和聊天里;specs、rules 和术语表描述的还是上个季度的系统 | sunset: never -->
|
|
7
|
+
|
|
8
|
+
在 `keelson land` 之前,以及审阅它的输出时,对你学到的每件事问一遍:
|
|
9
|
+
|
|
10
|
+
| 变更产生了 | 它去到 |
|
|
11
|
+
|---|---|
|
|
12
|
+
| 新的或改变了的稳定行为 | 能力的 spec,经由 delta(`land` 合并它) |
|
|
13
|
+
| 未来维护者会在意的理由 | spec 的 `Decisions`(`land` 折叠它们) |
|
|
14
|
+
| 新术语,或从此有了特定含义的术语 | `GLOSSARY.md` |
|
|
15
|
+
| 在模块间移动的职责,或新边界 | 限定在那些路径上的 rules;项目若维护架构文档则还有 `refs.architecture` |
|
|
16
|
+
| 带数字的质量目标 | spec,作为带 scenario 的需求 |
|
|
17
|
+
| 命令能检查的约束 | `config.yaml → check`(fitness 检查);随后散文规则可以收缩 |
|
|
18
|
+
| 走到验证阶段才发现的缺陷 | 一个回归测试,加上 ledger 里的 `Root cause:` |
|
|
19
|
+
| 已知但未做的工作 | 任务系统,或 `ROADMAP.md → Next`,带负责人 |
|
|
20
|
+
| 只在变更期间有意义的东西 | 哪儿也不去;随 change 目录留在 git 历史里 |
|
|
21
|
+
|
|
22
|
+
以上每一行在其目的地都是现在时。change 目录是脚手架,会被移除;留下来的是真相文件。
|
|
23
|
+
|
|
24
|
+
## 当前真相只重写,不追加
|
|
25
|
+
<!-- keelson: id=reconcile.rewrite | without: specs 变成按时间排列的日记;读者分不清哪一段描述的是今天的系统 | sunset: never -->
|
|
26
|
+
|
|
27
|
+
一条 spec、一条 rule、一行术语表说的是系统现在怎么工作。行为变化时,描述旧行为的那句话被替换,而不是在后面跟一句"从九月起现在是……"。变更的先后顺序在 git 里、在归档或折叠掉的 change 里、在点名了被否方案的决策行里。`keelson doctor` 会标出读起来像历史叙述的需求文本。
|
|
28
|
+
|
|
29
|
+
## 压缩:让被读到的东西保持小
|
|
30
|
+
<!-- keelson: id=reconcile.compact | without: 文档无限增长;常驻集合让每个会话都变贵,过时文本被当作现状读取 | sunset: never -->
|
|
31
|
+
|
|
32
|
+
`config.yaml → budgets` 给每种文档一个行数预算(INTENT、ROADMAP、NOW、GLOSSARY、spec、rule、change、handoff,以及作为整体的常驻 rules)。预算是**软压缩阈值**。Keelson 会在高频文档失控前自动重组存储:大型 spec 自动变成小型索引 + requirement/decision 分片,runtime 缓存自动回收。如果某个单独语义单元本身仍然过大,Agent 会在 RECONCILE 中自动改写或拆解,并重新验证结果。活跃 change/handoff 只是临时脚手架,不会演变成长期知识仓库。只有整理会改变产品语义、授权、兼容性或其他真正属于所有者的决策时才询问用户。
|
|
33
|
+
|
|
34
|
+
超过软预算后,对该文档做一遍压缩,逐段选择:
|
|
35
|
+
|
|
36
|
+
- **重写**得更短,现在时。
|
|
37
|
+
- **拆分**:按能力、范围或 bounded context 拆,当需求之间不再共享同一个目的时。
|
|
38
|
+
- **删除** git 已经保存的历史,以及没有任何东西依赖的事实。
|
|
39
|
+
- **移动**:把约束移到限定在其路径上的 rule,把计划项移到任务系统。
|
|
40
|
+
- **自动化**:把可检查的规则做进 `config.yaml → check`,散文缩成一个指针。
|
|
41
|
+
- **归档**已经停滞的变更(`keelson cancel` 并写明原因),而不是让它半开着。
|
|
42
|
+
|
|
43
|
+
`keelson doctor` 还会检测跨能力重复需求、闲置/过大的变更、膨胀的常驻 rules 和过期生成文档。Agent 在正常工程轮次里顺手消费这些信号并完成安全整理;只有整理会改变语义时才形成所有者可见的决策。
|
|
44
|
+
|
|
45
|
+
## 自动维护对用户不可见
|
|
46
|
+
<!-- keelson: id=reconcile.automatic | without: 所有者被要求执行清理命令、spec 变成巨型单文件,或者整理一直拖到本身成为一个项目 | sunset: never -->
|
|
47
|
+
|
|
48
|
+
把知识形态当成基础设施,而不是用户工作。当 `keelson context` 暴露内部 maintenance finding 时,在同一轮工程工作里自行解决,不要求所有者介入:
|
|
49
|
+
|
|
50
|
+
- **大型 specs** —— 不要通过摘要丢掉 requirement。`keelson land` 会自动把大型 capability 从单个 `spec.md` 变成有界索引 + `requirements/*.md` + `decisions/*.md`。总知识量可以持续增长,但每个高频读取文件保持小。
|
|
51
|
+
- **Rules** —— 按真实路径/作用域拆分并更新 `rules/index.md`;合并重复规则,能确定性检查的散文规则改为 fitness check。单条 rule 仍过宽时,自动重写成保留语义的最小不变量。
|
|
52
|
+
- **NOW / INTENT** —— 永远不拆分,自动重写成短小的当前状态;历史留给 git。
|
|
53
|
+
- **ADR / decisions** —— 项目使用 `refs.decisions` 时,一个长期决策一个 ADR;目录可以持续增加,但不要在每个会话全量注入 ADR。capability 局部决策自动拆成 `decisions/*.md`。
|
|
54
|
+
- **Runtime** —— session pointer 和 evidence log 都是缓存;Keelson 会在正常命令中顺手回收旧数据。
|
|
55
|
+
|
|
56
|
+
只有压缩会改变产品语义、授权、兼容性或其他真正属于所有者的决策时才询问用户。移动文件、更新索引、去重、删除历史叙述和缓存清理都属于内部维护,静默完成。
|
|
57
|
+
|
|
58
|
+
## 园艺节奏
|
|
59
|
+
<!-- keelson: id=reconcile.cadence | without: 只有疼了才看知识健康,到那时清理本身已经是一个项目 | sunset: never -->
|
|
60
|
+
|
|
61
|
+
Agent 在正常 context/reconcile 周期以及重要 landing 后重新评估知识健康。维护是持续、增量且静默的:始终让高频文档保持可读,而不是安排专门的清理日或要求所有者管理控制面。
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Shaping(成形)
|
|
2
|
+
|
|
3
|
+
在工件存在之前,把一个请求或想法变成共同的理解。先查事实,再提问,然后写回。有三层需要弄清,但不必一次全清:项目层(服务谁、永远不做什么,在 `INTENT.md`)、当前目标层(这个里程碑,在 `ROADMAP.md` 或任务系统里)、本次变更层(改变什么行为,别人怎样知道它做完了)。
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
界面工作按需加载 `frontend.md`;视觉与交互验收遵循 `frontend-review.md` 和 `frontend-delivery.md`。
|
|
7
|
+
|
|
8
|
+
## 先探索
|
|
9
|
+
<!-- keelson: id=shape.explore-first | without: 代理向用户询问它本可以自己读到的事实,浪费对方时间,还让对方学会跳过问题 | sunset: never -->
|
|
10
|
+
|
|
11
|
+
先读能回答问题的东西:代码、测试、`INTENT.md`、`ROADMAP.md`、specs、命中的 `rules/`,以及 `config.yaml` 里 `refs` 列出的文档。spec 的 `Decisions` 段或 `INTENT.md` 里已经记录的决策就是定论,不要再问。只有关于意图、优先级和取舍的问题才属于用户。
|
|
12
|
+
|
|
13
|
+
## 提问前先做假设审计
|
|
14
|
+
<!-- keelson: id=shape.assumption-audit | without: the agent solves a plausible but wrong problem, attributes invented beliefs to the owner, or asks a questionnaire before reading the repository | sunset: never -->
|
|
15
|
+
|
|
16
|
+
quick 工作存在实质性歧义时,以及每一个 spec 变更里,都要在读完仓库、开始实现之前做一次紧凑审计。不要展开私有思维链,只报告会影响决策的结果:
|
|
17
|
+
|
|
18
|
+
1. **已成立(Established)** — 用户或仓库确实说过的事实。
|
|
19
|
+
2. **方案所需假设(Required assumptions)** — 你准备采用的路径必须依赖、但还没人确认的条件。写成“这个方案要求 X 成立”,不要写成“你假设 X”。
|
|
20
|
+
3. **缺失信息(Missing)** — 无法从仓库查到的信息;按它能多大程度改变结果、边界、验收或难以撤销的选择来排序。
|
|
21
|
+
4. **假设错了会怎样(Failure if wrong)** — 指出这类工作最可能的一种失败模式,例如解决错问题、范围膨胀、兼容性破坏、没有测量就优化、不安全迁移,或当前任务真正相关的风险。
|
|
22
|
+
|
|
23
|
+
审计默认留在内部,只把短 write-back 真正需要的事实/假设写出来。没有关键缺口就按项目授权和默认值继续;存在由用户掌握且会改变结果的缺口时,按 `interview.md` 路由,只问一个最高价值问题,更新写回后重新判断。不要把审计清单展示给用户。
|
|
24
|
+
|
|
25
|
+
## 写回你的理解
|
|
26
|
+
<!-- keelson: id=shape.write-back | without: 代理按自己的解读去做;不一致要到代码写出来之后才暴露 | sunset: never -->
|
|
27
|
+
|
|
28
|
+
每个非平凡变更在创建任何东西之前,用 3 到 6 行写清:结果、边界(明确不做什么)、你发现的约束、成功的检验方式。把用户说的和你假设的分开。写回后默认继续;只有对应的 `confirm.quick|spec` 设为 `wait`,或仍存在真正属于所有者的未决决定时才等待。高风险动作仍按 `INTENT.md → Authorizations` 确认。
|
|
29
|
+
|
|
30
|
+
> 我的理解是:给 `/orders` 加偏移分页(`page`、`size`,默认 20),沿用 `rules/api.md` 里的统一响应封装;表格加分页器,不做无限滚动。假设:排序仍按 `created_at desc`。`npm test -- orders` 通过且分页器能渲染即为完成。
|
|
31
|
+
|
|
32
|
+
## 你所知道的东西有四种状态
|
|
33
|
+
<!-- keelson: id=shape.decision-states | without: 代理提出的建议后来被当成负责人的选择,而没人分得清 | sunset: never -->
|
|
34
|
+
|
|
35
|
+
在对话里和 `change.md` 里都把它们分开:
|
|
36
|
+
|
|
37
|
+
- **建议(Suggestion)** — 你推荐的方案及其后果。负责人选定之前不生效。
|
|
38
|
+
- **已确认(Confirmed)** — 负责人选定的。`## Decisions` 下的一行普通条目。
|
|
39
|
+
- **已授权(Authorized)** — `INTENT.md → Authorizations` 允许你独自决定的。决定、按已确认记录、继续。
|
|
40
|
+
- **未决(Open)** — 还需要答案的。`## Open questions` 下的一行,带 `— blocks: <slice>`。
|
|
41
|
+
|
|
42
|
+
必须在没有答案的情况下继续时,把工作假设写成 `## Decisions` 下的 `- (assumed) capability: …`。负责人没有传 `--confirm-assumptions` 之前,`keelson land` 拒绝折叠 assumed 行。
|
|
43
|
+
|
|
44
|
+
## 下一个切片可交付时就停止提问
|
|
45
|
+
<!-- keelson: id=shape.stop-rule | without: 代理要么用后面切片的问题把负责人问到筋疲力尽,要么在验收还没定义的切片上开工 | sunset: never -->
|
|
46
|
+
|
|
47
|
+
标准不是"项目里没有任何未知",而是:下一个切片有清楚的结果、边界和验收检查。关于后面切片的未决问题写进 `## Open questions` 并注明它阻塞什么,它不阻塞的工作继续。例如:下载权限未定,链接管理列表可以先建,但公开下载不能被默认打开。
|
|
48
|
+
|
|
49
|
+
## 访谈(只有 decision frontier 真正需要时)
|
|
50
|
+
<!-- keelson: id=shape.interview | without: 架构歧义被 Agent 默默猜测,或者每个 spec change 都变成强制问卷 | sunset: never -->
|
|
51
|
+
|
|
52
|
+
交互方式统一按 `interview.md`。spec 级变更**不等于**必须向用户提问:先自行解决仓库拥有的事实和可逆工程选择。工作涉及数据、安全、并发、兼容、错误处理/资源生命周期、运维、性能、UI/可访问性或 AI 行为时,只检查 `design-lenses.md` 里真正触发的行,把结果转成决定或证据义务。修改失败路径时,按其中的要求先写回归测试,再开始实现。
|
|
53
|
+
|
|
54
|
+
假设检查默认在内部完成。除非不确定性确实属于所有者,否则不要用抽象的“我们在假设什么?”开场;把它翻译成具体的用户行为或风险后果再问。明确要求“深挖这个方案”才沿相关决策树继续问到底;普通工作只要下一个安全切片准备好就停止。
|
|
55
|
+
|
|
56
|
+
## 授权
|
|
57
|
+
<!-- keelson: id=shape.authorization | without: 要么每一步都等批准,要么代理自己决定产品问题和生产操作 | sunset: never -->
|
|
58
|
+
|
|
59
|
+
| 情形 | 默认处理 |
|
|
60
|
+
|---|---|
|
|
61
|
+
| 已确认范围内、遵循项目约定的局部实现选择 | 决定、验证、继续 |
|
|
62
|
+
| 意图仍模糊;选择会改变体验、范围或长期承诺 | 给推荐和后果;由负责人选择 |
|
|
63
|
+
| 不可逆数据操作、生产修改、权限扩大、破坏兼容性 | 按 `INTENT.md → Authorizations` 明确确认 |
|
|
64
|
+
| 无关的优化、额外功能、大范围重构 | 提建议;不扩大变更 |
|
|
65
|
+
| 环境缺失、关键验收无法执行 | 标为受阻或部分验证;绝不伪造通过 |
|
|
66
|
+
|
|
67
|
+
模型越强,第一行越宽;第三行永远不变。
|
|
68
|
+
|
|
69
|
+
## 没有人能回答时
|
|
70
|
+
<!-- keelson: id=shape.unattended | without: 无人值守的会话要么永远卡在一个问题上,要么悄悄落地一个没人批准过的变更 | sunset: never -->
|
|
71
|
+
|
|
72
|
+
脚本化或无人值守的会话里,没有人能确认写回、批准计划。不要停滞,也不要跳过工件:写下理解和计划,把假设标为 `(assumed)`,在这些假设下构建和验证,落地前停下。在 `NOW.md` 里说明该变更等待审阅。审阅者随后可以同时看到计划和 diff,用 `--confirm-assumptions` 落地或拒绝。
|
|
73
|
+
|
|
74
|
+
## 探索(用户在思考,而非在提需求)
|
|
75
|
+
<!-- keelson: id=shape.explore-stance | without: 代理把方案强加给一个只想找人一起想的用户 | sunset: never -->
|
|
76
|
+
|
|
77
|
+
如果用户是在权衡选项而不是在下达任务,就采取思考伙伴的姿态:只读不写,铺开多个方向,勾勒取舍,给出有依据的推荐,让用户选。决策留在对话里;用户开口之前不建 change。
|
|
78
|
+
|
|
79
|
+
## 定大小的经验法则
|
|
80
|
+
<!-- keelson: id=shape.sizing | without: 代理在琐事上走仪式,或在契约变更上跳过规划 | sunset: 连续 50 个变更都不需要用户覆盖层级时 -->
|
|
81
|
+
|
|
82
|
+
- 负责人会想在代码存在之前先读一份计划吗?→ spec。
|
|
83
|
+
- specs 里有任何 `Requirement:` 变化、新增或消失吗?→ spec。
|
|
84
|
+
- 涉及迁移、外部依赖,或会跨会话的工作?→ spec。
|
|
85
|
+
- 你在为某个隐藏约束放弃显而易见的方案吗?→ spec,并记录备选。
|
|
86
|
+
- 否则,多个文件、意图清楚 → quick。单文件、行为不变 → trivial。
|