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
37 changes: 34 additions & 3 deletions .claude/skills/pm-dispatch/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -1818,10 +1818,41 @@ dev 用五项检查验证了它,其中一条是**反向证据**:`spec/src/api/an
第 3 条最容易被省掉,而省掉它就退化成最坏形态:前提不成立时 dev 自行改选,那正是**无人
裁决**的状态,且没有任何读数会显示它发生过。

**两条元判据 —— 一整族近似单默认不进决策箱(维护者 2026-08-07 决策箱第 2 轮拍板)。**
上面的「不升级四类」说的是**单张单**自带裁决;这两条说的是**一族形状相同的单**不必逐张
问 —— 族里第一张已经裁过,后来的默认继承那条裁决。重复立卡不是谨慎,是拿维护者的时间
买同一个答案。

- **静默丢弃的声明,默认并入既有拒收集。** 适用判据:一个**已声明的键**在组件的某一支上
被**静默忽略**,而更早的裁决已把同一个键在**兄弟支**上定成**响亮的编写期错误**。此时
新支**默认并入既有拒收集** —— 复用母单的裁决直接入队派发,⛔ 不为它另开决策箱槽位;
只有两支之间存在**真实语义差异**时才重开。出处:#5714 把 `pool`-on-sqlite 裁成编写期
错误之后,#5931(`memory` 支)仍占了一个槽位,而它只是那条裁决的一词之差的外延;同族
重复整周都在发生。⚠️ **边界必须与本条同段读,否则这条捷径会被用过头**:继承的是**裁决
连同它的理由**,不是「拒收」两个字 —— 母单的理由**被实测为分支特有**时本条不适用。
#5739(维度侧)的理由是「拒收会连带拒掉今天已经能跑的查询」,该理由在**度量面上被
证伪**,所以 #5918 另裁一次是对的。判法固定:把母单的理由拿到新支上复核一遍,理由不
成立就回正常升级路径,别让「同一个键」这个表面相似度替你做判断。
- **一个操作两个实现,默认治理侧胜出。** 适用判据:同一个操作存在两处实现,且两处行为
不一致。**带治理的那一侧**(权限闸、用户同意、去重、审计留痕)是**默认幸存者**,另一侧
**改绑到它并删除** —— 不是两侧对齐,也不是保留双写。反向裁只在**产品语义明确要求**时
成立,且必须把那条语义写进裁决正文,而不是默认成立后再补理由。出处:cloud#896
(hostname)即此形定案;cloud#1147 的三个待答问题(重装 = UPSERT、卸载 = 软停用、外部
词表 = manifest id)按本条全部落在治理侧;objectstack#4636 的 B 选项是同一形状。留着
未治理的那一侧等于给权限闸留一条旁路,而「声明即强制」要堵的正是那条旁路。

Whenever a dev returns `needs_decision` that passes the bar above, an issue
is too vague to dispatch, or rework has failed twice:

1. **Default: the decision lives ON the issue it belongs to — never a new
1. **先刷新卡片的前提 —— 落卡与复升级都适用。** 决策卡写下的每条前提(某个在飞
PR 还没合、某能力还不存在、某文件还是那个形状)都是**有保质期的读数**:main
一天 ~18 合并,跨仓事实按小时变。落卡**之前**、以及把一张旧卡重新推到维护者
面前**之前**,逐条复核一遍,失效的就地改写或撤卡 —— **隔夜没动过的卡,默认按
「前提未经验证」处理,不是按「还在等答复」处理。** 出处是决策箱第 2 轮的实测:
cloud#1148 的 A/B 卡在**写下前 ~50 分钟**就已失效(它等的那个上游 PR 已经合了),
cloud#812 一张卡带三条过时前提。前提过期的卡比没有卡更贵 —— 维护者会照着一个
不存在的世界做裁决,而卡面上没有任何读数会显示这件事发生过。
2. **Default: the decision lives ON the issue it belongs to — never a new
issue.** Post the analysis as a comment on that issue, add the
`needs-user-decision` label, drop it from the active queue. The label is
the maintainer's inbox (filter `label:needs-user-decision` shows
Expand All @@ -1832,7 +1863,7 @@ is too vague to dispatch, or rework has failed twice:
when the decision has no natural anchor — it spans several issues (file
one, link it from each rather than duplicating the analysis) or arose
with no issue of its own.
2. The analysis, wherever it lands (English, per the language policy):
3. The analysis, wherever it lands (English, per the language policy):
background / the concrete question / options / your recommendation /
related issues, PRs, branches。**每个方案必须沿三条固定评估轴
分析,这是决策分析的核心原则,不是可选项:**
Expand All @@ -1858,7 +1889,7 @@ is too vague to dispatch, or rework has failed twice:
绝不让 AI 能声明一个运行时不兑现的能力。
推荐意见必须基于这三条轴给出理由;三轴冲突时如实呈现权衡,交维护者
拍板。
3. If the session is interactive, additionally raise it via `AskUserQuestion`;
4. If the session is interactive, additionally raise it via `AskUserQuestion`;
the labeled issue remains the durable record either way. **Never** answer
a product/architecture question on the maintainer's behalf.

Expand Down
42 changes: 39 additions & 3 deletions skills/objectstack-pm-dispatch/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -439,24 +439,60 @@ Named non-escalation classes — act immediately:
- **Sequencing and dependency ordering** between technical tasks.
- **Verification strategy** — what regression pass a risky-but-decided change
needs. That is scoping the work, not deciding it.
- **A declaration silently dropped on a new arm, when a sibling arm already has
a ruling.** When a declared key is silently ignored on one arm of a component
and an earlier ruling already made that same key a **loud authoring error** on
a sibling arm, the new arm **joins the existing rejection set by default** —
reuse that ruling, queue it, dispatch it; do not spend a fresh decision on a
one-word extension of an answer you already have. Only a genuine **semantic
difference between the arms** reopens the question. **State the boundary in the
same breath as the default, or the shortcut gets over-applied:** what carries
over is the ruling **together with its rationale**, never the verdict alone.
When the original rationale was measured to be arm-specific — it held on the
face it was ruled on and is disproved on the new one, as a "refusing this would
reject usage that already works" argument does the moment the new arm has no
such working usage — the default does not apply and the new arm earns its own
decision. The test is mechanical: re-check the original rationale against the
new arm *before* reusing the verdict. Sharing a key name is not sharing a
reason.
- **Two implementations of one operation.** When one operation has two
implementations and they disagree, the side that already carries the
**governance** — authorization gates, user consent, de-duplication, audit
trail — is the **default survivor**; the other is rebound onto it and deleted.
Not reconciled, not kept as a second writer. The ungoverned side wins only
when **product semantics explicitly demand** it, and that semantic goes into
the decision text rather than being supplied afterwards as justification.
Keeping both implementations keeps a path around the gates — exactly what
`declared = enforced` exists to close.
- A developer agent's `needs_decision` that, on review, falls into the classes
above: answer it yourself with the decision and rationale; do not relay it
upward.

When something *does* pass the bar:

1. **The decision lives ON the issue it belongs to — never a new issue.** Post
1. **Refresh the card's premises first — before writing it, and again before
re-escalating it.** Every premise a decision card states (an in-flight change
has not landed, a capability does not exist yet, a file still has this shape)
is a **reading with a shelf life**: an active main branch takes on the order
of a dozen or more merges a day, and cross-repository facts move on an hourly
scale. Re-check every premise immediately before posting the card — and again
before pushing an older card back in front of the maintainer — then rewrite or
withdraw whatever no longer holds. **A card that sat overnight untouched is a
card whose premises are unverified, not merely a card that is waiting.** An
expired premise is worse than no card: the maintainer rules on a world that no
longer exists, and nothing on the card shows that this happened.
2. **The decision lives ON the issue it belongs to — never a new issue.** Post
the analysis as a comment there, add `needs-user-decision`, drop the issue
from the active queue. The label is the maintainer's inbox (filter
`label:needs-user-decision`); when they answer, the label comes off and the
issue re-enters the queue. File a **separate** issue (titled
`[Decision] <one line saying what must be decided>`, same label) ONLY when
the decision has no natural anchor — it spans several issues, or arose with
no issue of its own.
2. Write the analysis with: background, the precise question, the options, your
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.**
3. If the session is interactive, additionally ask the maintainer directly; the
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.

Expand Down
Loading