Loft(放样) 是做什么的?
在切割钢板之前,先确保形状完美。 造船工匠会先进行全尺寸放样,绘制船体线形并验证,然后才切割第一块钢板。Loft 将同样的秩序应用于设计问题:当文字已无法解决问题时——两个看似合理的答案,都无法通过讨论证伪——就构建一个廉价的可运行制品,让项目负责人(“船长”)与其交互,并将该交互反馈转化为决策。
职责契约。 团队负责构建制品;船长的唯一工作就是做出反应——而那个反应就是决策。制品是用于观察的工具,绝不是可交付成果的抢先起步。
何时进行放样
- 设计问题在文字中陷入僵局:反复重新表述,仍然无法确定(例如“路径页面应该是什么样子”、“这个状态模型感觉对吗”)
- 导航图(navigator map)上带有
loft任务卡片 - 规格讨论陷入“我们得先亲眼看看”的局面
不要进行放样的情况:
- 该问题可以通过仓库中的证据或直接询问船长来回答(那是访谈,不是放样)
- 目标本身不明确(那是迷雾——请使用
/oh-my-claudecode:ask-navigator) - 答案已存在于 ADR(架构决策记录)中(不要重新放样已确定的决策)
- 所谓的“设计问题”实际上是一个 bug(这属于调试者的管辖范围)
选择分支
根据问题在问什么来选择。选错了分支,整个制品就白费了。
逻辑分支——模型正确吗?
适用于关于状态、业务规则、数据形状或算法的问题(例如“重考时解锁状态会回退吗?”、“这个 reducer 在边界情况下能正常工作吗?”):
- 隔离出承载决策的核心——状态机、reducer、schema 或算法——作为一个纯模块:无 DOM、无 I/O、无框架。编写方式应确保一旦形状被确认,它能够原封不动地移入真实代码库。
- 将其封装在一个简单的可点击 HTML shell 中:每个场景对应一个按钮,按顺序遍历有问题的边界情况,每次点击后完整显示当前状态。
- 当模块被确认可以提取后——它将通过 launch(启动)作为实际工作重新进入代码库。在放样期间,
main分支保持不变,shell 则留在分支上。
UI 分支——它应该看起来什么样?
适用于关于形状和布局的问题(例如“步骤式还是卡片式?”、“进度信息放在哪里?”):
- 同一条路由,三种在结构上不同的变体——信息架构、导航模型、内容密度。仅在样式上不同的变体毫无意义:三种换皮方案如同墙纸。
- 页面上有一个切换器可以循环显示这些变体;尽可能嵌入到现有产品中,以便真实数据密度能够测试设计效果,而不是用三行整洁的假数据。
- 确认后,决策被转移,而变体作为“为何如此设计”的记录,留在分支上。
规范
- 一个命令即可运行——仓库中最简单的现有 serve 命令;如果
file://模块的 CORS 会出问题,则将模块内联到 shell 中。在几秒内加载;除了仓库已有的构建步骤外,无需额外构建。 - 无持久化、无测试、无抽象、无错误处理(仅处理正常路径)。制品应该是一个你绝对不想发布的东西——这些规则就是为了保持其“可丢弃”的特性。
- 预计初版形状会受到质疑:在同一个会话中于分支上修改。船长确认最终形状即为决策;一个无人质疑的制品通常回答了一个没人关心的问题。
- 制品的整个生命周期只有几分钟构建时间加一个会话的决策时间。如果它开始向生产代码方向扩张,立即停止:那是启动(launch)工作,不是放样(loft)。沉没成本正是本技能要防止的失败模式。
- 一次放样回答一个问题。两个问题就是两次放样——或者是一个原本被误认为是一个问题的、实际上包含两个问题。
纳入答案
制品是证据,而非终点。当船长做出反应后:
- 将决策记录在其归属位置——Issue 评论、规格文档中的“实施决定”部分、或待定决策记录中——使用船长自己的措辞加上一行原因说明。如果有比文字更精确的片段(如 reducer、状态机、schema),可以内联在那里,并标记为已放样(lofted)。
- 将制品推送到
loft/<名称>分支。它永远不会合并:它将作为主要来源,供未来的读者在需要了解决策的“为什么”时打开查看。 - 制品中的任何内容都不会进入
main分支——对于逻辑分支,确认后的模块通过 launch 作为实际工作重新进入;对于 UI 分支,根据决策从头构建真实页面。
范围与非目标
- Loft 产出的是答案,而非可交付物:无运行时、无状态文件、无永久运行的东西。
- 它不进行诊断(那是调试器的工作),不描绘迷雾(请使用
/oh-my-claudecode:ask-navigator),不批准自己的答案(船长的反应是唯一的验收标准)。 - 它不替代 seams 审批:Loft 展示的 UI 只是一个形状;其对应的测试 seams 仍需在 C2 阶段审批。
完成标准
船长已做出反应,答案已记录在决策归属位置,制品已存放在其分支上——并且制品中没有一行代码进入 main 分支。