Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .changeset/published-pm-dispatch-three-axis-decision-frame.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
---
---

docs(skills): 已发布 skill `objectstack-pm-dispatch` 的决策框架由两轴升为三轴 —— 新增「实际业务需求」轴,内核泛化后搬 (#5451)

#5130 把内部 agent 协议的决策评估轴由两条扩为三条,但同一套框架在**已发布目录**里还有
一份镜像 —— `skills/objectstack-pm-dispatch/SKILL.md`(#4607 发布,`metadata.domain:
process`,无 `metadata.internal`,第三方 ObjectStack 项目可 `npx skills add` 安装),
它仍是两轴。#5130 刻意把范围钉在 `.claude/`(改发布内容是用户可见变更),本单补齐,
两份文本重新同构。

维护者 2026-08-06 在 #5451 裁决 **B(泛化内核后搬)**,而不是原样搬或不搬:

- **新增 Axis ①「real business need」,排在两条原有轴之前**——每个方案先问它服务的是
真实存在的业务场景还是投机性能力面;判据要求**实测而非推断**(谁在写这个键、谁在读
这个能力、示例应用与真实部署里的用法),「读起来像有用」不作数;无拉动的声明面按
**implementation-first** 处置(收窄声明使 `declared = enforced`,或让词表随未来实现
回归),而不是为声明补实现;**已发布但零消费的能力不因沉没成本获得豁免**。并写明这条
轴会**改变结论**:技术形状相同的两个发现可以仅凭这条轴得出相反裁决(一个因无业务拉动
退役,另一个因真实应用自证方向而裁「响亮拒绝而非退役」),只看后两条轴会得出同一个
答案。原两轴(项目长远合理性、防 AI 写代码/写元数据 app 犯错)**原文保留**,仅编号后
移为 Axis ② / ③。
- **泛化纪律**:去掉内部版绑定的「我们是一个创业项目」自我描述,也不带入本仓专属先例
单号 —— 发布版是 project-agnostic 的,把我们的处境写进别人的决策机器,会让安装方的
PM agent 按错误前提做决策。**扩张姿态改由安装方项目自己的 conventions 文件声明**
(核心面尚在成形时从紧、平台面稳定后放宽),接进该 skill 既有的 config-over-hardcoding
机制:`conventionsFile` 配置项说明与「Adapting this loop to your project」表格各加
一处,与分支命名、release-note 产物、测试命令走同一条覆写路径。
- 全文 7 处两轴措辞逐处升三轴:分诊一节的 `the deep two-axis`、升级流程的
`the two fixed axes below`、`#### The two-axis decision frame (binding)` 标题、
框架首句与收尾句的 `**both** axes`,以及**嵌入的 dev-agent 模板**里的
`Analyze every option on two fixed axes:` 与 `Justify your recommendation on both
axes`。模板那两处是关键:PM 按三轴呈报而开发 agent 按两轴上报,业务轴每次都要 PM 事后
补。文中仅保留一处 `the other two axes`,指的是 Axis ② / ③ 这「另外两条」,是三轴语境
下的正确表述。
- `metadata.version` 1.0 → 1.1:已安装 1.0 的第三方据此看到这是一次内容修订。

**空 frontmatter 是刻意的,不是遗漏**,沿 #4607 发布 PR 与 #5130 的同一先例:`skills/`
不随任何 npm 包发布(没有 package 的 `files` 含它,分发路径是 `npx skills add` 直读
仓库),因此没有包可署名 —— 署一个包会凭空造出一条其发布物未变更的 release 记录,并把
PM skill 的说明塞进那个包的 CHANGELOG。本次变更对**装这份 skill 的人**可见,但不发布
任何包。
60 changes: 46 additions & 14 deletions skills/objectstack-pm-dispatch/SKILL.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,7 +22,7 @@ compatibility: >
(MCP server) with issue/label/PR write access.
metadata:
author: objectstack-ai
version: "1.0"
version: "1.1"
domain: process
tags: pm, dispatch, backlog, triage, multi-agent, delivery, github, escalation, upstream
---
Expand DownExpand Up@@ -99,7 +99,7 @@ single-repository project work with no configuration at all.
| `repos` | `string[]` | `[backlogRepo]` | Every repository work may land in. Used for label setup and for validating routing labels. |
| `batch` | `number` | `3` | Maximum developer agents in flight at once. |
| `mode` | `"subagent" \| "cloud"` | `"subagent"` | Dispatch backend — see [Dispatch backends](#dispatch-backends). |
| `conventionsFile` | `string` | first existing of `AGENTS.md`, `CLAUDE.md`, `CONTRIBUTING.md` | Repository-relative path to the file that defines gates, branch rules, release-note artifacts and review policy. Injected by path into every dispatch. |
| `conventionsFile` | `string` | first existing of `AGENTS.md`, `CLAUDE.md`, `CONTRIBUTING.md` | Repository-relative path to the file that defines gates, branch rules, release-note artifacts, review policy and the capability-expansion stance. Injected by path into every dispatch. |
| `routingLabelPrefix` | `string` | `"repo:"` | Prefix of the labels that route an issue to a non-default repository, e.g. `repo:hotcrm-web`. Inert when `repos` has one entry. |

**Unknown keys are an error, not a hint.** If the file contains a key not in
Expand DownExpand Up@@ -182,7 +182,7 @@ classify each:
- **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 two-axis
shipped capability. The label alone is the inbox entry; the deep three-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.
Expand DownExpand Up@@ -449,23 +449,44 @@ When something *does* pass the bar:
no issue of its own.
2. Write the analysis with: background, the precise question, the options, your
recommendation, and the related issues / PRs / branches — **and analyze
every option on the two fixed axes below.**
every option on the three fixed axes below.**
3. 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 two-axis decision frame (binding)

Every option in an escalation is analyzed on **both** axes. This framing is the
core of the escalation, not decoration.

**Axis ① — long-term architectural soundness for *this* project.** Which option
#### The three-axis decision frame (binding)

Every option in an escalation is analyzed on **all three** axes. This framing is
the core of the escalation, not decoration.

**Axis ① — real business need.** Does this option serve a business scenario that
**actually exists**, or a speculative capability surface? Ask it of every option
*first*, before the architecture argument, because it can retire the question
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
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
would read the same, and that would be the wrong answer.

**Axis ② — long-term architectural soundness for *this* project.** Which option
matches where the project is going and a sustainable architecture — no
workarounds, contract-first — rather than which is cheapest today. **Name the
long-term cost of any patch-style option explicitly.** "We can special-case it
here" is a valid option only when its future removal cost is stated.

**Axis — making AI-authored code structurally hard to get wrong**, and
**Axis — making AI-authored code structurally hard to get wrong**, and
especially AI-authored ObjectStack **metadata**. Prefer the option that
prevents the mistake at authoring time — a strict schema, publish-time
validation that rejects loudly, declared = enforced — over consumer-side
Expand All@@ -475,7 +496,7 @@ 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 **both** axes. If they conflict,
Your recommendation must be justified on **all three** axes. If they conflict,
present the trade-off honestly and let the maintainer decide.

### 9. Round report, then next round
Expand DownExpand Up@@ -571,7 +592,17 @@ 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 two fixed axes:
Analyze every option on three 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.
- 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.
Expand All@@ -580,7 +611,7 @@ Analyze every option on two 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 both axes; if they conflict, present the
Justify your recommendation on all three 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
Expand DownExpand Up@@ -799,6 +830,7 @@ them into every dispatch:
| Files owned by a release process that a code PR must never touch | conventions file |
| Test / typecheck / lint commands per package | conventions file |
| Merge policy (merge queue, serial merge, maintainer-only) | conventions file |
| Capability-expansion stance the business-need axis reads (tight by default, or permissive) | conventions file |
| Which repositories exist and which is the backlog | `.claude/pm-dispatch.json` |
| Recorded architecture decisions the escalation bar defers to | the project's ADR directory |

Expand Down
Loading