From 47f5058a2e05a7338a46216d61e0ffd914ce7dd9 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 19 Aug 2026 00:48:59 +0000 Subject: [PATCH] docs(skills): elevate startup scope discipline to a first-class fourth axis across all four synced copies of the decision frame MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Maintainer ruling (2026-08-18), verbatim: 「9769 应该是四维度分析,但是还在写三轴。从实际业务需求,从平台长远合理性,从避免AI写代码犯错的角度,从创业阶段不扩散需求的角度。」 Fixes #9791 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01WswfK2yNYT9hNnMH6TzAwL --- .claude/agents/os-dev.md | 11 ++--- .claude/skills/pm-dispatch/SKILL.md | 16 ++++---- scripts/check-skill-frame-freshness.mjs | 2 +- scripts/check-skill-frame-sync.mjs | 35 ++++++++++------ skills/objectstack-pm-dispatch/SKILL.md | 53 ++++++++++++++----------- 5 files changed, 67 insertions(+), 50 deletions(-) diff --git a/.claude/agents/os-dev.md b/.claude/agents/os-dev.md index 1a191c50d6..a4211b0f99 100644 --- a/.claude/agents/os-dev.md +++ b/.claude/agents/os-dev.md @@ -284,22 +284,23 @@ dispatch prompt 只携带每单增量(裁决引文、裁决 / PM-机制假设分 issue 对塑造公开契约的某个决定欠规格 —— spec/Zod schema、API 形状、命名、元数据语义 —— 或两种读法通向两种架构时:不猜,不写投机代码。返回 `status: "needs_decision"`,把每个问 题连同选项、成本与你的推荐写进 `open_questions`。 -**Analyze every option on three fixed axes — this framing is the core of the escalation, +**Analyze every option on four fixed axes — this framing is the core of the escalation, not decoration:** - **Real business need**(实际业务需求)— 该方案服务的是**真实存在的业务场景**,还是投 机性能力面?证据必须**实测** —— 谁在写这个键、谁在读这个能力、示例应用与真实部署怎么 - 用;「读起来像有用」不作数。**创业阶段聚焦原则**(维护者 2026-08-04:这是创业项目,核 - 心能力优先):能力扩张默认从紧,无拉动的声明面按 implementation-first 处置,已发布零 - 消费的能力不因沉没成本获得豁免。这条轴会改变结论,不是陪衬。 + 用;「读起来像有用」不作数。这条轴会改变结论,不是陪衬。 - **Long-term soundness for THIS project**(项目长远合理性)— 哪个方案符合北极星方向与 可持续架构(no workarounds、contract-first)—— 补丁式选项的长期代价要明说。 - **Making AI-written code — especially AI-authored metadata apps — hard to get wrong** (防 AI 写代码犯错,尤其是 AI 编写的元数据 app)— 优先选在编写时点就结构性防错的方案 (严格 schema、publish 时响亮拒绝的校验、declared = enforced),而非消费端宽容 —— 宽 容的消费端恰是 AI 生成错误藏身并扩散的地方。 +- **Startup scope discipline**(创业阶段不扩散需求)— **创业阶段聚焦原则**(维护者 + 2026-08-04:这是创业项目,核心能力优先):能力扩张默认从紧,无拉动的声明面按 + implementation-first 处置,已发布零消费的能力不因沉没成本获得豁免。 -Your recommendation must be justified on all three axes;三轴冲突时如实呈现权衡,交维护 +Your recommendation must be justified on all four axes;四轴冲突时如实呈现权衡,交维护 者拍板。同样,`main` 在你脚下碎了、依赖未合并、CI 基础设施故障时,返回 `blocked`(附证 据)—— 先重试到足以确认不是你的改动。 diff --git a/.claude/skills/pm-dispatch/SKILL.md b/.claude/skills/pm-dispatch/SKILL.md index 1bacb78126..0261999aa7 100644 --- a/.claude/skills/pm-dispatch/SKILL.md +++ b/.claude/skills/pm-dispatch/SKILL.md @@ -591,20 +591,20 @@ grep `),复升级时逐条**跑**一遍,零命中/变形的就地改写 `[Decision] <一句话>` 卡。③ **答复/代裁到手,裁决记录是一个原子动作,四件同笔**(维护者 2026-08-13) :鲜度门(录前重读晚于正文最后编辑的评论,有修正的先调和正文)/ 状态转换同笔(决策标签或 finding 定 级换结果态,永不留挂)/ `Blocked-by:` 活性现验(合并一半也算解除,耗尽行同笔删)/ 条件已判即判(输入已知的就地判掉);案例与机械两旗见 `references/dispatch-runbook.md`。 -**每个方案必须沿三条固定评估轴分析,这是决策分析的核心原则,不是可选项:** +**每个方案必须沿四条固定评估轴分析,这是决策分析的核心原则,不是可选项:** - **实际业务需求** — 它服务的是**真实存在的业务场景**,还是投机性能力面?判据要求**实测**(谁在 - 写这个键、谁在读、示例应用与真实部署的用法),「读起来像有用」不作数。**创业阶段聚焦原则**( - 维护者 2026-08-04 指示:「我们是一个创业项目,应该先专注于核心能力」):能力扩张默认从紧,无拉 - 动的声明面按 implementation-first 处置,已发布零消费的能力不因沉没成本获得豁免。这条轴会改 - 变结论,不是陪衬。 + 写这个键、谁在读、示例应用与真实部署的用法),「读起来像有用」不作数。这条轴会改变结论,不是陪衬。 - **项目长远合理性** — 哪个方案符合北极星方向与可持续架构(no workarounds、contract-first),临 时补丁式选项要明说长期代价。 - **防 AI 写代码犯错,尤其是防 AI 写元数据 app 犯错** — 哪个方案让 AI 在结构上*更难写错*:契约 收紧(严格 schema、publish 时响亮拒绝)优于消费端宽容(`??` 回退、静默容错)—— 宽容恰是 AI 批 量犯错被掩盖的温床;声明即强制,绝不让 AI 声明一个运行时不兑现的能力。 +- **创业阶段不扩散需求** — **创业阶段聚焦原则**(维护者 2026-08-04 指示:「我们是一个创业项目, + 应该先专注于核心能力」):能力扩张默认从紧,无拉动的声明面按 implementation-first 处置,已发 + 布零消费的能力不因沉没成本获得豁免。 -推荐意见必须基于这三条轴给出理由;三轴冲突时如实呈现权衡,交维护者拍板。**标准四棱卡面块是落卡与 +推荐意见必须基于这四条轴给出理由;四轴冲突时如实呈现权衡,交维护者拍板。**标准四棱卡面块是落卡与 升级的必备件**(四棱维护者 2026-08-11 接受;标准块/摘要视图/批量决裁通道 2026-08-18 裁定「同意」—— 块标准化把提取从 LLM 理解题降级成 grep),每张 `needs-user-decision` 卡落卡即带、⛔ 不留待维护者到 场再补。固定形状:首行**机器可寻固定标记** ``(转义拼写写入,写后回读核 @@ -614,7 +614,7 @@ defer/remove);③ AI-agent error-resistance(闭合枚举优于自由结构、响 scope discipline(remove 优于 declare-and-maintain,每个已声明的键都是永久义务);一行推荐 + 字母选 项(A/B/…);**一行强制置信缺口(「本分析看不见什么」)** —— 案例(2026-08-15):两张四棱同向、低风 险、全绿、已复核的 PR 仍因分析看不见的方向性前提被整体作废 —— 推荐是输入,永不是放行,人工地板不变。 -四棱是三条评估轴的卡面序列化,同一个框架不是第二套;也是分诊代裁置信门的输入(见分诊职责)。交互会 +四棱是四条评估轴的卡面序列化,一一对应,同一个框架不是第二套;也是分诊代裁置信门的输入(见分诊职责)。交互会 话可另发 `AskUserQuestion`,带标签的 issue 恒为持久记录。 **摘要视图与批量决裁**(同一 2026-08-18 裁定;实施既有批量裁决 2026-08-15 原话「还是等我批量决裁 @@ -677,5 +677,5 @@ scope discipline(remove 优于 declare-and-maintain,每个已声明的键都是 | `scripts/pm/dispatch-gates.mjs` | 文件面 → 该跑的门禁族(派发令取数) | | `scripts/pm/os-regen-merge.sh` | 碰生成物 PR 的 merge 四步序(防静默吞并与锚点倒退) | | `scripts/pm/ensure-pm-labels.sh` | pm 标签词表的幂等创建 | -| `check:skill-frame-sync` / `-freshness` | 三轴决策框架四份拷贝的同构与新鲜度 | +| `check:skill-frame-sync` / `-freshness` | 四维决策框架四份拷贝的同构与新鲜度 | | `guard-main-checkout` / `guard-shared-stash` hooks | worktree-first 与 stash 禁令的机械面 | diff --git a/scripts/check-skill-frame-freshness.mjs b/scripts/check-skill-frame-freshness.mjs index 62f19958b0..10e0ef8448 100644 --- a/scripts/check-skill-frame-freshness.mjs +++ b/scripts/check-skill-frame-freshness.mjs @@ -818,7 +818,7 @@ function selfTest() { label: 'stale tree + authoritative ref → ERROR naming the stale files (the #5866 shape)', run: () => evaluate({ root: dir, ref: current }), expect: 'error', - wants: [/STRUCTURALLY BEHIND/, /\.claude\/agents\/os-dev\.md/, /2 axes: long-term-soundness/, /3 axes: business-need/, new RegExp(REMEDY.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))], + wants: [/STRUCTURALLY BEHIND/, /\.claude\/agents\/os-dev\.md/, /3 axes: long-term-soundness/, /4 axes: business-need/, new RegExp(REMEDY.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))], }); cases.push({ label: 'the SAME stale tree, fetch impossible → degrades to WARN, exit 0, same diagnosis', diff --git a/scripts/check-skill-frame-sync.mjs b/scripts/check-skill-frame-sync.mjs index b1302537ad..c042f627e3 100644 --- a/scripts/check-skill-frame-sync.mjs +++ b/scripts/check-skill-frame-sync.mjs @@ -172,6 +172,11 @@ export const AXIS_MAP = [ zh: /防 ?AI ?写(?:代码|元数据)/, en: /making AI-(?:written|authored) code/i, }, + { + id: 'startup-scope-discipline', + zh: /创业阶段不扩散/, + en: /startup(?:-phase)? scope discipline/i, + }, ]; /** Numerals the count sentences are allowed to be written in. */ @@ -631,22 +636,22 @@ function selfTest() { ' **Long-term soundness for THIS project**', ), expect: 'red', - wants: [/internal-dev/, /declares 3 axes but 2 axis entries/], + wants: [/internal-dev/, /declares 4 axes but 3 axis entries/], }, { - // The #5130 shape, coherent: one side becomes a consistent two-axis frame. - label: 'one copy coherently rewritten to two axes → red (cross-copy count)', + // The #5130 shape, coherent: one side becomes a consistent three-axis frame. + label: 'one copy coherently rewritten to three axes → red (cross-copy count)', copies: () => { let c = mutate( base, 'internal-dev', '- **Long-term soundness for THIS project**', ' **Long-term soundness for THIS project**', ); - c = mutate(c, 'internal-dev', 'on three fixed axes', 'on two fixed axes'); - return mutate(c, 'internal-dev', 'on all three axes', 'on all two axes'); + c = mutate(c, 'internal-dev', 'on four fixed axes', 'on three fixed axes'); + return mutate(c, 'internal-dev', 'on all four axes', 'on all three axes'); }, expect: 'red', - wants: [/do not agree on the NUMBER of axes/, /#5130/, /2 axes {2}internal-dev/], + wants: [/do not agree on the NUMBER of axes/, /#5130/, /3 axes {2}internal-dev/], }, { // Regression pin for the draft defect described in soft(): the two-axis form @@ -659,8 +664,13 @@ function selfTest() { '- Making AI-authored code — especially AI-authored metadata — structurally hard', ' Making AI-authored code — especially AI-authored metadata — structurally hard', ); - c = mutate(c, 'published-dev', 'Analyze every option on three fixed axes:', 'Analyze every option on two fixed axes:'); - return mutate(c, 'published-dev', 'Justify your recommendation on all three axes', 'Justify your recommendation on both axes'); + c = mutate( + c, 'published-dev', + '- Startup scope discipline — do not grow the declared surface', + ' Startup scope discipline — do not grow the declared surface', + ); + c = mutate(c, 'published-dev', 'Analyze every option on four fixed axes:', 'Analyze every option on two fixed axes:'); + return mutate(c, 'published-dev', 'Justify your recommendation on all four axes', 'Justify your recommendation on both axes'); }, expect: 'red', wants: [/do not agree on the NUMBER of axes/, /2 axes {2}published-dev/], @@ -698,7 +708,7 @@ function selfTest() { label: 'the binding sentence is removed → red (extraction failure, not a skip)', copies: () => mutate( base, 'published-pm', - 'Your recommendation must be justified on **all three** axes.', + 'Your recommendation must be justified on **all four** axes.', 'Your recommendation should be sensible.', ), expect: 'red', @@ -708,7 +718,7 @@ function selfTest() { label: 'the declaring sentence is removed → red (extraction failure, not a skip)', copies: () => mutate( base, 'internal-dev', - '**Analyze every option on three fixed axes', + '**Analyze every option on four fixed axes', '**Weigh the options sensibly', ), expect: 'red', @@ -718,11 +728,11 @@ function selfTest() { label: 'a frame count mention drifts from the frame → red', copies: () => mutate( base, 'published-pm', + '#### The four-axis decision frame (binding)', '#### The three-axis decision frame (binding)', - '#### The two-axis decision frame (binding)', ), expect: 'red', - wants: [/a mention of the frame states 2 axes while the frame itself has 3/], + wants: [/a mention of the frame states 3 axes while the frame itself has 4/], }, { label: 'AXIS_MAP misaligned (zh patterns swapped) → red, proving the map is load-bearing', @@ -731,6 +741,7 @@ function selfTest() { { id: 'business-need', zh: AXIS_MAP[1].zh, en: AXIS_MAP[0].en }, { id: 'long-term-soundness', zh: AXIS_MAP[0].zh, en: AXIS_MAP[1].en }, AXIS_MAP[2], + AXIS_MAP[3], ], expect: 'red', wants: [/do not agree on the axis NAME SEQUENCE/], diff --git a/skills/objectstack-pm-dispatch/SKILL.md b/skills/objectstack-pm-dispatch/SKILL.md index 62f6c3dd8d..832aaa65df 100644 --- a/skills/objectstack-pm-dispatch/SKILL.md +++ b/skills/objectstack-pm-dispatch/SKILL.md @@ -230,7 +230,7 @@ waiting one more round. - **Maintainer confirm (`needs-user-decision`)** — design cards, feature or contract-shape proposals, multi-week programs needing appetite and sequencing, anything touching stored-data migration shape or removing a - shipped capability. The label alone is the inbox entry; the deep three-axis + shipped capability. The label alone is the inbox entry; the deep four-axis analysis is written when the card is actually taken up. - **Repair first** — a body truncated by GitHub's sanitizer cannot be dispatched. Comment the repair instruction and move on. @@ -641,14 +641,14 @@ When something *does* pass the bar: no issue of its own. 3. Write the analysis with: background, the precise question, the options, your recommendation, and the related issues / PRs / branches — **and analyze - every option on the three fixed axes below.** + every option on the four fixed axes below.** 4. If the session is interactive, additionally ask the maintainer directly; the labeled issue remains the durable record either way. **Never** answer a product or architecture question on the maintainer's behalf. -#### The three-axis decision frame (binding) +#### The four-axis decision frame (binding) -Every option in an escalation is analyzed on **all three** axes. This framing is +Every option in an escalation is analyzed on **all four** axes. This framing is the core of the escalation, not decoration. **Axis ① — real business need.** Does this option serve a business scenario that @@ -657,19 +657,10 @@ the core of the escalation, not decoration. instead of answering it. The evidence must be **measured, not inferred**: who writes this key, who reads this capability, how the project's example apps and real deployments use it today. "It reads like it would be useful" does not -count — and neither does "we already shipped it": a **shipped-but-unconsumed -capability gets no sunk-cost exemption**. A declared surface with no pull is -handled **implementation-first** — narrow the declaration until -`declared = enforced` (retire it, or park the vocabulary and let it return with -the implementation) rather than building implementation to justify a declaration -nobody asked for. **How tight that default should be is your project's call, not -this skill's:** declare the capability-expansion stance in your conventions file — -tight while the core surface is still forming, more permissive once it is -stable — and this axis reads it from there, like every other project-specific -rule. This axis **changes verdicts** rather than decorating them: two findings +count. This axis **changes verdicts** rather than decorating them: two findings of identical technical shape can be ruled opposite ways on it alone — one declared surface retired for lack of pull, another kept and made to *reject -loudly* because a real app proved the direction. On the other two axes they +loudly* because a real app proved the direction. On the other three axes they would read the same, and that would be the wrong answer. **Axis ② — long-term architectural soundness for *this* project.** Which option @@ -688,7 +679,19 @@ reader turns a whole generation of wrong metadata into something that "works" until it does not. Never let an agent declare a capability the runtime does not honour. -Your recommendation must be justified on **all three** axes. If they conflict, +**Axis ④ — startup scope discipline.** Do not grow the declared surface while +the core is still forming. "We already shipped it" earns nothing: a +**shipped-but-unconsumed capability gets no sunk-cost exemption**. A declared +surface with no pull is handled **implementation-first** — narrow the +declaration until `declared = enforced` (retire it, or park the vocabulary and +let it return with the implementation) rather than building implementation to +justify a declaration nobody asked for. **How tight that default should be is +your project's call, not this skill's:** declare the capability-expansion +stance in your conventions file — tight while the core surface is still +forming, more permissive once it is stable — and this axis reads it from there, +like every other project-specific rule. + +Your recommendation must be justified on **all four** axes. If they conflict, present the trade-off honestly and let the maintainer decide. ### 9. Round report, then next round @@ -798,17 +801,12 @@ or two readings of the issue lead to different architectures: make no guess, write no speculative code. Return status "needs_decision" with each question, the options, their costs, and your recommendation in open_questions. A wrong guess shipped is far more expensive than a round-trip to the maintainer. -Analyze every option on three fixed axes: +Analyze every option on four fixed axes: - Real business need — does the option serve a business scenario that ACTUALLY EXISTS, or a speculative capability surface? Ask this first. The evidence must be MEASURED, not inferred: who writes this key, who reads this capability, how the project's example apps and real deployments use it today. "It reads like it - would be useful" does not count, and a shipped-but-unconsumed capability gets - no sunk-cost exemption. A declared surface with no pull is handled - implementation-first — narrow the declaration until declared = enforced - (retire it, or park the vocabulary until the implementation arrives) rather - than building implementation to justify the declaration. How tight the default - is comes from the project's conventions file, not from this template. + would be useful" does not count. - Long-term architectural soundness for THIS project — which option matches a sustainable architecture (no workarounds, contract-first), not which is cheapest today. Name the long-term cost of any patch-style option. @@ -817,7 +815,14 @@ Analyze every option on three fixed axes: publish-time validation that rejects loudly, declared = enforced) over consumer-side tolerance. Lenient consumers are where AI-generated errors hide and multiply. -Justify your recommendation on all three axes; if they conflict, present the +- Startup scope discipline — do not grow the declared surface: a + shipped-but-unconsumed capability gets no sunk-cost exemption. A declared + surface with no pull is handled implementation-first — narrow the declaration + until declared = enforced (retire it, or park the vocabulary until the + implementation arrives) rather than building implementation to justify the + declaration. How tight the default is comes from the project's conventions + file, not from this template. +Justify your recommendation on all four axes; if they conflict, present the trade-off and let the maintainer decide. Return "blocked" (with evidence) when the default branch is broken under you, a