Skip to content

docs(pm-dispatch): decision-analysis writes the platform-first rule behind the app-repo recommendation special case - #24280

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-24256-platform-first-rule
Oct 18, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-24256-platform-first-rule

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #24256
Clause-②: no

What changes

One file, .claude/skills/pm-dispatch/references/decision-analysis.md, section 〈应用仓推荐序特例〉. The maintainer's standing word of 2026-10-18, 「平台相关的功能,应该尽量先改平台。」, becomes the general rule of the section, verbatim and dated; the existing blocked-card special case stays byte-identical as its application; the two corollaries the ruling batch used are added; provenance is written in the corpus register (comment ids and case names as plain words, no hash prefix).

The section after the edit (L44 to L50):

## 应用仓推荐序特例

- 「平台相关的功能,应该尽量先改平台。」(维护者 2026-10-18 逐字,裁决台账 6245607810,批 362)
- 能力先建在平台(spec、objectstack 运行时、objectui 渲染器);应用仓(cloud、hotcrm)不自建替代。
- 阻塞源是平台缺陷 ⇒ 恒荐等待;⛔ 不荐绕行(形状容错、复刻平台规则)、不荐劈半落地。
- 过渡唯维护者明裁;应用仓临时扩展平台契约,仅当平台卡与移除卡同一裁决立出。
- 应用仓裁决立出的平台卡取被裁卡优先级,⛔ 不降档。推论出处:cloud 2932 A、cloud 2924 A。

Where each item of the dispatch's deliverable lands:

item line carried as
1. the dated rule, verbatim L46 the sentence byte-for-byte (fullwidth comma and full stop kept), then 「维护者 2026-10-18 逐字」
1. gloss: platform scope, built there first L47 「能力先建在平台(spec、objectstack 运行时、objectui 渲染器)」
1. gloss: no local substitute in an app repo L47 「应用仓(cloud、hotcrm)不自建替代」
1. gloss: unless the maintainer rules the interim explicitly L49 「过渡唯维护者明裁」
2. the existing special case, as the rule's application L48 unchanged, byte-identical (the diff does not touch the line)
3. corollary (a) L49 「应用仓临时扩展平台契约,仅当平台卡与移除卡同一裁决立出」
4. corollary (b) L50 「应用仓裁决立出的平台卡取被裁卡优先级,⛔ 不降档」
5. provenance L46, L50 ledger comment 6245607810 and batch 362 in the rule's attribution; the cases cloud 2932 A and cloud 2924 A as the corollaries' source, after the operative sentence ends

Line budget: 50 before, 50 after, ceiling 50 (headroom 0, no raise)

Five lines added in the section are paid by five lines removed at the head of the file, all by deleting content the file already carries elsewhere; nothing is re-wrapped. Each removed clause and where it survives:

removed (old line) survives at
L3 「见 SKILL.md 〈升级与决策〉节的四轴框架」 new L3 「四轴见 SKILL.md 〈升级与决策〉」, the same pointer
L3 「本文只放适用面、批流程与两个固定形状」, a table of contents the section headings themselves: 〈常设决裁批流程〉, 〈落卡分析模板〉, 〈四棱卡面块固定形状〉; 「适用面」 is now the clause on new L3
L5 heading 「## 适用面」 and its blank lines L6, L8 the scope sentence now opens the file on L3, so the section has nothing left to hold
L7 「只约束 needs-user-decision 卡与决策箱讨论的四维分析。」 new L3, word for word, with its implicit subject 「本文」 spelled out

Measured before folding: git grep -n "适用面" -- .claude scripts/pm at the base answers three lines, all in this file (old L3, the old heading L5, and L17, the batch flow's own unrelated 「适用面 =」 term), so no reader greps the heading.

Every line of the file is within 120 bytes (the ratchet's line scan: zero offenders, zero exemptions; L3 and L46 to L50 measure 118, 120, 118, 119, 109 and 116 bytes).

Where this differs from the suggested route

  • The suggested section shape had the rule on one line. Measured: the verbatim sentence with its brackets is 57 bytes and the attribution 29, so the gloss (platform scope with the two repository names, the app-repo prohibition, the interim exception) cannot share the line within 120 bytes. The rule takes L46 and L47, and the interim exception rides L49 beside corollary (a), which is the form such an interim takes.
  • The suggested fold measured three freed lines, as the seat counted: the scope clause cannot join the old intro line within 120 bytes, so the intro would wrap to two. The fourth line comes from dropping the intro's table of contents, which the headings already carry, so the intro and the scope clause fit one line (118 bytes).
  • The provenance is split between the rule's attribution (ledger id and batch) and corollary (b)'s tail (the two cases, labelled as the corollaries' source), because no single line had room for all of it.

Verification

All on the final head 46a29bff (the branch commit e17629d8 plus a merge of origin/main 93b4acb5, which touched only scripts/pm/dispatch-gates*.mjs). The gate list was derived from the merge base with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 17 commands, the same 17 the seat derived. Each exit code was captured before any pipe:

node scripts/check-closing-keyword-parity.mjs                    :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test        :: exit 0
node scripts/check-comment-mask-corpus.mjs                       :: exit 0
node scripts/pm/check-harness-current.mjs --self-test            :: exit 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0
pnpm check:agent-test-spelling                                   :: exit 0
pnpm check:cross-package-test-inputs                             :: exit 0
pnpm check:doc-authoring                                         :: exit 0
pnpm check:driver-memory-census                                  :: exit 0
pnpm check:gitlink-declared                                      :: exit 0
pnpm check:nul-bytes                                             :: exit 0
pnpm check:pm-governed-merges                                    :: exit 0
pnpm check:pm-skill-id-lint                                      :: exit 0
pnpm check:pm-skill-ratchet                                      :: exit 0
pnpm check:refd-timer-probe                                      :: exit 0
pnpm check:skill-frame-sync                                      :: exit 0
pnpm check:watch-hint-literal                                    :: exit 0
pnpm check:skill-frame-freshness   (local-only, outside the derivation) :: exit 0
  • check:doc-formula-expressions first answered exit 3 (PREREQUISITE NOT MET: @objectstack/formula and @objectstack/lint unbuilt in this worktree). It was built under the shared verify lock (VERDICT command-exit 0) and re-run to exit 0. The exit 3 measured nothing and is not a finding.
  • Key verdict lines: check-skill-line-ratchet: .claude/skills/pm-dispatch/references/decision-analysis.md is 50 lines (ceiling 50; headroom 0); check-skill-id-lint: 87 file(s) clean (pattern /#[0-9]{3,}/g); check-skill-frame-sync: the one declared copy of the decision frame is internally coherent; check-skill-frame-freshness: the decision frame in this tree is current with origin/main; check-nul-bytes: OK.
  • --ran reconciliation: 17 derived famil(ies) accounted for — 17 run, 0 NOT-MEASURED (a DERIVED zero — all 17 recorded an exit code and none of them is 3).
  • Control-byte self-scan of the changed file: no hits.
  • No ablation: the diff is agent-protocol prose and changes no tested behaviour.

Acceptance notes

  • .claude/** is unpublished, so skip-changeset is declared with this PR's labels and there is no changeset.
  • Governed surface, Tier S (.claude/**): this PR stays draft for the seat's in-seat contract review.
  • The commit's trailer pair is the model-free one AGENTS.md prescribes.

维护者速读(草稿)

  • 改了什么: 决策分析写法的〈应用仓推荐序特例〉一节,写入您 2026-10-18 的原话「平台相关的功能,应该尽量先改平台。」作为总则:属于平台的能力(spec、objectstack 运行时、objectui 渲染器)先在平台做,应用仓(cloud、hotcrm)不自己做替代品,临时过渡只由您明裁。原有「平台缺陷阻塞就等,不绕行、不劈半」一句原样保留,作为总则在被阻塞应用仓卡上的用法。另加两条推论:应用仓临时扩展平台契约,必须在同一次裁决里同时立平台卡与移除卡;从应用仓裁决拆出的平台卡沿用被裁卡的优先级,不降档。
  • 为什么改: 批 362 里几张应用仓卡都可以在应用仓里绕过平台缺口,您都裁为等平台或推动平台修;这句话此前只记在台账里,席位排推荐序时读不到。写进参考文件后,今后同类卡的推荐会默认指向平台,不会出现应用仓先做一个替代品、平台那半张卡却排在后面没人做的局面。
  • 风险与代价(含回滚): 只改一个内部席位读的参考文件,不发版、不影响客户;文件行数 50 → 50,未抬上限,所腾出的行来自文件开头的目录句与重复的适用面小节,内容无丢失。回滚 = 还原这一个提交。
  • 席位意见:
  • 你要做的: 无需动作;席位内达档复核通过后由席位落地。如对两条推论的措辞有异议,在卡上一句话说明即可。

Generated by Claude Code

…behind the app-repo recommendation special case

The maintainer's standing word becomes the general rule of the
app-repo recommendation-order section, verbatim and dated, with the
existing blocked-card special case kept byte-identical as its
application and the two corollaries the ruling batch used: a temporary
extension of a platform contract only with the platform card and the
removal card filed in the same ruling, and a platform card filed from
an app-repo ruling taking the ruled card's priority.

Paid at net zero lines (50/50, ceiling 50) by folding the scope
section into the intro line and dropping the intro's table of contents,
which the section headings already carry.

Claude-Session: https://claude.ai/code/session_01QBcLjVCmcWbZEk6qhYMib2
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 46a29bff469900385beed49a696152d2c88fe250
Local-runs: probe — the seat ran check-skill-line-ratchet.mjs in a detached worktree at this head (with check-skill-id-lint.mjs, check-skill-frame-sync.mjs, check-nul-bytes.mjs and a no-path dispatch-gates.mjs --commands derivation beside it, all read-only, all exit 0, 17 commands derived) because the zero-headroom ratchet is the card's one hard constraint and a reading taken from the report alone would be recall
Scope: .claude/skills/pm-dispatch/references/decision-analysis.md (whole file at the head, 50 lines, every line measured in bytes) + .claude/skills/pm-dispatch/SKILL.md 〈升级与决策〉 (the frame the new L3 points at) + scripts/check-skill-frame-sync.mjs L375 (names this file as a non-copy) + scripts/pm/check-skill-line-ratchet.mjs (the CEILINGS row 50) + the ruling ledger 6245607810 on card 12708 (read this act: the sentence verbatim, batch 362, cloud 2924 → A) + the card's Related line (cloud 2932 A, comment 6228116462)

Face: governed rules text (.claude/**, Tier S) — no published schema, no narrowing line, Clause-②: no. Inputs: card 24256 (body, the retriage 6245975001, triage's grade 6246839296, the claim 6247078083, the order 6247082079, the report 6247336403) and PR 24280 (body, file list, the net diff +5/−5 at the head above); the head's check-runs at this read were 18 success, 12 skipped, 6 in progress with the five required contexts already success or skipped — the landing check reads them again, this record judges the diff. Rendered in seat at 2026-10-18T07:57Z; the seat's served tier equals the value of CONTRACT_REVIEW_TIER.

① Derived judgments

  1. The rule. L46 carries the maintainer's sentence byte-for-byte as the card and the ledger quote it (「平台相关的功能,应该尽量先改平台。」, fullwidth comma and full stop), dated 2026-10-18, marked 逐字, with the ledger comment id and the batch number — the card's 「verbatim, dated, as the rule」. Its gloss on L47 (platform = spec, the objectstack runtime, the objectui renderer; built there first; cloud and hotcrm build no substitute) is the card's second sentence; the card's 「unless the maintainer rules the interim explicitly」 is L49's opening clause 「过渡唯维护者明裁」. Right — nothing of the card's statement is dropped, and nothing is added to it.
  2. The special case. L48 is the pre-edit line, untouched by the diff (the context line between the additions): the rule's application to blocked app-repo cards, as the order required 「stays」. Right.
  3. The corollaries. L49 「应用仓临时扩展平台契约,仅当平台卡与移除卡同一裁决立出」 is corollary (a) clause for clause (temporary extension; platform card and removal card; the same ruling). L50 「应用仓裁决立出的平台卡取被裁卡优先级,⛔ 不降档」 is corollary (b) (the platform half filed from an app-repo ruling; the ruled card's priority; never lower). The provenance tail 「推论出处:cloud 2932 A、cloud 2924 A」 sits after the operative sentence's full stop, no #, as the order's item 5 spells it; the ledger id and batch ride the rule's own attribution on L46. Right — the split provenance is forced by the 120-byte line habit and loses no reference; check-skill-id-lint reads 87 files clean in seat.
  4. The paid lines. Five added, five removed, 50 → 50 against ceiling 50 (ratchet green in seat; no raise, no re-wrap). The removed head of the file was one pointer plus a table of contents plus a one-line 〈适用面〉 section; new L3 keeps the pointer (「四轴见 SKILL.md 〈升级与决策〉」) and the scope clause word for word (「只约束 needs-user-decision 卡与决策箱讨论的四维分析」). The dropped table of contents (「本文只放适用面、批流程与两个固定形状」) was already stale on main — it named three parts while the file has four sections, 〈应用仓推荐序特例〉 among them — so its loss is a correction, not a cost. Readers of the folded heading: git grep "适用面" on main hits only this file (the old L3, the old L5 heading, and L17's unrelated 「适用面 =」 term in the batch flow, which survives as L13). Right, lossless.
  5. The frame. The new lines state the rule and its corollaries; none paraphrases an axis, and check-skill-frame-sync in seat still reads one declared copy (SKILL.md) with 90 markdown files scanned for undeclared copies. The pointer on L3 is the same cross-reference the old L3 carried. Right.
  6. Widths. Every line ≤ 120 bytes (the file's habit): L46 120, L47 118, L48 119, L49 109, L50 116, L3 118; the widest pre-existing lines (L12, L29, L42) were already 120. No table row, pin 0.
  7. Public surface: none. .claude/** is unpublished; no code, gate or workflow changed. The card's done-when (the dated rule and the two corollaries in the reference; check-harness-current reads the change at the next seat boundary) is met by the diff, the second half at landing.

② Semver level

.claude/** publishes nothing: skip-changeset declared in the pr_create stroke (the PR carries skip-changeset, documentation, size/s), Check Changeset success on the head (its post-label re-run skipped, in the roster). Body line 2 Clause-②: no: right, no published accept set moves.

③ Boundary flags

  • Dev deviations D1–D3 (the rule on two lines, the fourth freed line from the stale table of contents, the split provenance) are measurements against the seat's suggested route, which was optional; each is accepted above (①.1, ①.4, ①.3).
  • D4: origin/main moved to 93b4acb5 mid-run (the dispatch-gates lists Dogfood Regression Gate as "scheduled BY YOUR PATHS" for a route-ledger.ts change, but its if: skips pull_request and merge_group, so neither PR CI nor the derived commands run the dogfood pins (main red after #24009) #24073 landing); the dev merged it (merge commit 46a29bff over e17629d8) and re-derived from the new base — the right handling of a STALE derivation, and the branch commit's own diff is unchanged.
  • D5: the harness's model-named trailer and two-line attribution block versus AGENTS.md's model-free pair and single footer — AGENTS.md wins, as on every PR this shift; the commit carries Co-authored-by: Claude and the session trailer, the body one footer.
  • D6: the dev removed its worktree after the PR opened and sent the report through the shared checkout's fleet-write/dispatch.mjs read-only; the shared checkout read clean (git status empty, HEAD 93b4acb5) at this review. Accepted; the order's 「⛔ never edit it」 held.
  • open_questions: none. out_of_scope_findings: none. mcp_calls 0.

Implemented-by: claude/issue-24256-platform-first-rule
Reviewed-by: session_01QBcLjVCmcWbZEk6qhYMib2

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

维护者速读

改了什么:决策分析写法(.claude/skills/pm-dispatch/references/decision-analysis.md)〈应用仓推荐序特例〉一节,把您 2026-10-18 的原话「平台相关的功能,应该尽量先改平台。」逐字、带日期写成总则(第 46 行,注明台账 6245607810、批 362),第 47 行写清「平台」指 spec、objectstack 运行时、objectui 渲染器,应用仓(cloud、hotcrm)不自建替代;原有「阻塞源是平台缺陷就等,不绕行、不劈半」一句原样保留(第 48 行)作为总则在被阻塞应用仓卡上的用法;再加两条推论:应用仓临时扩展平台契约,只能在同一次裁决里同时立平台卡和移除卡;从应用仓裁决拆出的平台卡沿用被裁卡的优先级,不降档;过渡只由您明裁。文件 50 行 → 50 行,未抬上限:腾出的五行来自文件开头一句过时的目录句(它只数了三节,文件实有四节)和与之重复的〈适用面〉小节,适用面那句话原文并入第 3 行,内容无丢失。

为什么改:批 362 里几张应用仓卡(cloud 2924、2948、2925、2774)都能在应用仓里绕过平台缺口,您全部裁为等平台或推动平台修。这句话此前只在台账里,席位排推荐序时读不到;写进参考文件后,同类卡的推荐默认指向平台,不会再出现应用仓先做替代品、平台那半张卡排在后面没人做的局面。

风险与代价(含回滚):只改一份给席位读的内部参考文件,不发版、不动代码与门禁;行数棘轮、编号 lint、四轴框架同步三项门禁席内在该提交上实跑全绿。风险是两条推论的措辞是席位和开发从您的裁决案例归纳的,若与您的本意有出入,改一行即可。回滚 = revert 本 PR 一个提交。

席位意见:ACCEPT。席内达档契约复核 PASS(6247374427,head 46a29bff)逐条对照了卡面与台账:原话逐字一致,特例行未动,两条推论与卡上 (a)(b) 逐句对应,出处不带 #。head 38 个 check 26 绿、12 预期跳过、0 红。Tier S(.claude/**)由席位落地,不需要您的批准。

你要做的:无。若对两条推论的措辞(第 49、50 行)有异议,在卡上一句话说明,席位补一张一行 PR。

席位核对

Seat domain:skills#1 · session_01QBcLjVCmcWbZEk6qhYMib2 (sunhaolin) · read 2026-10-18T07:58Z · head 46a29bff469900385beed49a696152d2c88fe250 · verdict: ACCEPT (Tier S — the seat lands it after the two pre-landing checks)

Implemented-by: claude/issue-24256-platform-first-rule
Reviewed-by: session_01QBcLjVCmcWbZEk6qhYMib2

  1. Shape. Draft PR against main; body line 1 Fixes #24256, line 2 Clause-②: no (copied from claim 6247078083). The only closing keyword in the body is that line; the cloud cases are written as plain words, no other card number sits beside a closing verb. File list: .claude/skills/pm-dispatch/references/decision-analysis.md (+5/−5). Head 46a29bff = the branch commit e17629d8 plus a merge of origin/main 93b4acb5 (the dispatch-gates lists Dogfood Regression Gate as "scheduled BY YOUR PATHS" for a route-ledger.ts change, but its if: skips pull_request and merge_group, so neither PR CI nor the derived commands run the dogfood pins (main red after #24009) #24073 landing, scripts/pm/dispatch-gates*.mjs only). mergeable true, mergeable_state clean at this read.
  2. Premise and acceptance, read by the seat. The card's done-when first half is met by the diff: the dated rule verbatim (L46), its gloss (L47), the untouched special case (L48), corollaries (a) and (b) (L49, L50), provenance without # (contract review 6247374427 ①.1–①.3); the second half (check-harness-current reads the change) is this seat's at the landing. 50 lines before and after against ceiling 50, paid by the stale table-of-contents line and the duplicate 〈适用面〉 section (①.4, lossless); no frame copy (①.5); every line ≤ 120 bytes (①.6).
  3. Gates — check-runs pinned to head 46a29bff. 38 completed: 26 success (the five required contexts Lint & Repo Gates, TypeScript Type Check, Test Core, Governed Surface Queue Guard success and Build Core skipped by the selector; Check Changeset; every Lint · and Type Check · lane; the four claim checks; Dogfood Regression Gate), 12 skipped all in the roster (check-expected-skips.mjs --pr 24280 OK, exit 0), 0 failed, 0 in progress (2026-10-18T07:57Z). check-governed-merges.mjs --pr 24280: GOVERNED, Tier S, .claude/** ×1, +5/−5 under the 3000-line threshold. The dev's local subset: 17 of 17 derived families exit 0 (--ran reconciled, 0 NOT-MEASURED); the seat's own probe of the ratchet, id-lint, frame-sync and nul-bytes gates at this head: exit 0.
  4. Changeset. None owed (.claude/** unpublished); skip-changeset declared in the pr_create stroke and present, Check Changeset success. The seat concurs: the dev's declaration confirmed, not forwarded.
  5. Report hygiene. mcp_calls 0; api_writes 2 relay strokes (pr_create with assignee and labels, run 39109167839; the report comment 6247336403), no PATCH/PUT/DELETE; one git push of the commit (the earlier empty-branch push was the interrupted first run's). Deviations D1–D6 answered in the contract review ③. The first run of this card was killed by a container restart before any edit; the resumed run continued in the same worktree and branch.
  6. Out of scope. None reported; none found by the seat.
  7. Landing (Tier S). Pre-landing check ①: the ## Contract review PASS record 6247374427 names this head. Check ②: every check green or an expected skip. Next act: relay pr_ready then automerge_enable; the probe-table landing comment follows when the queue ref is gone and origin/main carries the commit. subscribe_pr_activity is live on this PR since 2026-10-18T07:55Z. The lane's serial dev slot is free; the queue (pm:queue ∩ domain:skills) is empty.

Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants