Skip to content

docs(north-star,pm-dispatch): the feature axis — area:* labels, the 「路」 section as an ordered list of feature points, cross-layer features as parent + per-layer sub-issues, domain:* retreats to file ownership (#19483) - #19488

Merged
hotlong merged 7 commits into
mainfrom
claude/issue-19483-feature-axis-charter
Sep 21, 2026

Conversation

@os-project-manager

@os-project-manager os-project-manager commented Sep 21, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #19483

Clause-②: no

The feature axis lands in the three steps the card names: area:* as the planning axis, the North Star's road section as an ordered list of feature points, and domain:* retreating to file ownership.

The maintainer's words this implements (verbatim, chat 2026-09-21)

「关于任务的车道,我觉得现在是有问题的,应该是按照功能点划分车道我更容易判断优先级和安排,而且一个功能点应该覆盖从协议开始到运行时到前端。不应该按照我们的文件夹划分。」 / 「或者是否建议再加一组label?」 / 「有了功能轴之后我应该怎么安排任务?」 / 「包括我们应该划分哪些功能轴」 / 「把北极星的「路」那一节改成可读的功能点顺序 立」.

Tier and landing

Tier H (docs/NORTH-STAR.md and .claude/** in one diff, one path hit makes the whole PR Tier H). The maintainer merges this by hand. Draft, no ready flip, no auto-merge, no labels.

✅ The eleven-value axis list is ruled. The maintainer confirmed it on the card with ONE amendment, verbatim (chat, 2026-09-21): 「19483 api-integration 简化成 api 其他同意。」 — recorded as the card's ruling comment 5754985448. Round 2 of this PR carries the rename: the value is area:api in all four places it is spelled (the label row, the axis in api-backend.json and integration-system.json, and the three roadmap lines), its customer capability unchanged. The other three open questions were ruled A in the same comment: platform-core stays file-level devpath, the label objects stay in objectstack + objectui, and the four readers keep riding in the glossary row with no ceiling raise.

Step 1 — area:*

  • scripts/pm/ensure-pm-labels.sh gains eleven rows, in two repos (objectstack + objectui), not the five-repo loop: a feature point spans 协议 → 运行时 → 前端, which is those two. cloud is parked (北极星「现在不做」), objectos is the docs/site repo, hotcrm is the exemplar app whose platform gaps are filed upstream. The reasoning is written into the file beside the rows; widening the loop is a vocabulary decision, not a maintenance edit. check:pm-label-desc-cap reads 38 descriptions (was 27), longest 100 characters.
  • SKILL.md 〈状态模型〉 gains the area:* glossary row with the card's text.
  • The four named readers ride in that row rather than on their own line under 「一个标签存在当且仅当有具名读者」. That is the one deviation from the card's letter, and it is a ratchet consequence, measured below — the same fold the Charter (ruling #202 B): the dev queue is product-only — tooling cards close at first grading, broken gates are deleted not repaired, at most one tooling dev in flight, and tooling is a first-touch label with named readers #19457 ratchet comment records for tooling. The row is exempt from the 120-byte line rule and the readers are still named and greppable: git grep -n 'area:' -- .claude/skills/pm-dispatch/SKILL.md returns the row with all four.
  • All fifteen docs/qa/platform-checklist/areas/*.json carry a top-level axis, item ids untouched. No schema extension was needed: the gate has no unknown-top-level-key rule, and pnpm check:platform-checklist is green on the added key (15 areas, 264 items, exit 0).
    • One mapping cannot be expressed with a top-level field: the card sends platform-core's docs-portal items (platform-core.docs-audience-gate, platform-core.docs-portal-render, both P1) to studio while the rest of that area is devpath. The file carries devpath; a per-item axis is out of this card's scope. Flagged for the maintainer under Open questions on the card.

The roadmap section, rewritten in round 3

The maintainer read the first version and said, verbatim (chat, 2026-09-21): 「19488 路上的功能点写的很奇怪,真的是平台总体的功能清单吗?怎么感觉是几个issue」. He was right: it was one card plus the checklist's currently-failing P0 items — a to-do list, not the platform's feature map. Round 3 replaces that one section; everything else in this PR is as reviewed.

What it is now: six blocks, one per step of the road the North Star already measures, and inside each block one line per feature point at capability level — a customer-visible capability that runs from the protocol through the runtime to the frontend. The end-user capabilities (records, access, workflow, reports, identity, files, i18n) sit at the step where the road first needs them, which is where the app is first run and seen. The 路步 column is gone because the block position is the step, the docs-authoring feature keeps its 「清单项待写」 slot at step ①, and the page's own rules hold: no counts, no pass/fail status, no new headings, and the ledger is not copied here.

The completeness claim is mechanical, not editorial. The feature points are derived by grouping every item in docs/qa/platform-checklist/areas/*.json so that each item belongs to exactly one line. The two totals: 264 items on disk, 264 mapped — zero unmapped, zero double-mapped, zero ids the ledger does not have — across 76 feature points in a 95-line section. The per-item listing is on the card, in the round-3 os-dev-report.

Round 4 (one commit, docs/NORTH-STAR.md only, +4/−2): the round-3 at-tier review (5755471665, PASS) named one line as misdescribing its items and one placement as debatable; both fixed — the CEL formula pair (formula-stdlib-matrix, formula-gates) now has its own feature-point line and the REST construction line no longer claims it; lifecycle-retention-sweep (ADR-0057 retention) moved off the packaged-object line onto its own. Totals unchanged: 264 items, 264 mapped, 0 unmapped, 0 double-mapped; 78 feature points.

Round 5 (merge commit, no rebase): origin/main moved (#19506 entered the maintainer's 插队 / 契约面卡 tiers into the 取卡全序; #19502 the handover protocol) and conflicted with this PR's 取卡全序 edit in SKILL.md and core-rules.md. Both sides are the maintainer's rulings, so the merge composes them: 「取卡全序:维护者直派插队卡(出处三件)> 契约面卡(判据见 references/lanes/spec.md)> 标签序」 and 「标签序:priority:p0 > pm:blocking > 功能点位次 > target: 板上项 > p1 > p2 > p3 > 无级」, identical in both files; the tie-break 「同级先 Bug 再卡龄」 stays on SKILL.md's following line (the composed line would exceed the 120-byte cap) and core-rules.md's summary defers to it. Everything else takes main's side. Ratchet: SKILL.md 815/819 (main's own count; this PR net zero), core-rules 151/151.

Step 3 — domain:* retreats to file ownership

  • 〈域车道〉 now says in one line that domain:* decides file ownership (anchoring, hot-file serial, single-claim paths) and is not a queue or a priority unit.
  • 〈候选与批次〉: the candidate order reads 「功能点位次」 — the parent's position in 「路上的功能点」 — ahead of the board and the priority ladder, and at most one feature point per axis is in flight unless the file surfaces are disjoint.
  • 〈分诊座位职责〉: a cross-layer feature point (two or more of spec / 运行时 / 前端) is filed as ONE parent carrying area:* + pm:epic + the checklist item's priority, plus per-layer sub-issues ordered by Blocked-by:. 〈Epic 子树车道〉 now names cross-layer feature points in its delegation line, which is what makes the existing epic mechanism the default for that case, and 多仓协调 规则 2 is aligned from 每仓一子单 to 逐层子单.
  • references/core-rules.md mirrors all four rules in place.
  • references/lanes/*.md: zero edits, as a measured reading, not a skipped step. No lane charter describes a per-domain queue as the order of work. Instrument reachability is shown by the control word: 「车道」 hits 31 times across those ten files, while the order vocabulary (队列/全序/取卡/候选顺序/排序/优先序/按域/逐域) produces exactly two hits, both about the merge queue (lanes/cli.md line 17, lanes/ui.md line 26). Since the card's instruction there is "delete or re-point, never add", the correct edit count is zero.

The ratchet — paid in place, no ceiling raised

check:pm-skill-ratchet is green with both files exactly at their ceilings: SKILL.md 813/813, core-rules.md 151/151, widest SKILL.md table row 342/342.

Three lines were added and three retired. Each retirement was checked for a surviving home rather than assumed:

retired from SKILL.md where the content still lives
「唯一例外 packages/lint 等与 spec 相交的 devx 面…」 (域车道) the 域车道 table's own domain:devx row, plus references/lanes/spec.md 范围 (「同含围着 spec 契约转的工具链…」 / 「一般开发工具面留 devx」)
「座位在编以 label:pm:seat 索引为准,每车道…每席恰一张。」 (域车道) 全体座位的不变量 (「一 PM 恰管一车道,一车道由一组座位管,一席一贴」) and 座位贴协议's first line; the label object's own description carries the fleet-board half
「sweep 与首触定级只对多车道仓,单车道仓机械三务自理。」 (分诊座位职责) 多仓协调 carries both halves — 「多车道仓…中央分诊是 domain:*/type/定级的唯一生产者」 and 「机械三务 = 自扫 sweep、自打 type、自做 finding 首触定级」

Two clauses moved rather than died: 「同级先 Bug 再卡龄」 moved from the order line to the line below it, and 「优先非豁免」 was dropped there because the 状态模型 priority:p0 row states it (「⛔ 不豁免同文件串行、深度等待与认领协议」).

The exact count the card asks for. One ruled line could not be paid: the reader list as its own bullet under 「一个标签存在当且仅当有具名读者」 needs SKILL.md 814 against a ceiling of 813 — one line. Everything payable was paid (three retirements), the length rule blocks folding it into that bullet (the bullet is 117 bytes and the shortest self-contained reader line is 114), and every other ceilinged file in the map stands at headroom 0, so no reference file can absorb it. ⛔ No ceiling was raised. The readers therefore ride in the byte-exempt glossary row; if the maintainer wants them as a separate rule line, the raise is 813 → 814.

Verification

  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derives 37 families on this diff; all 37 were run on the final head c55c02e with exit codes captured before any pipe, all exit 0, and --ran reconciles 37 derived / 37 run / 0 NOT-MEASURED / 0 UNRUN with no stale-tree warning.
  • Named in the dispatch and green: check:pm-skill-ratchet, check:pm-label-desc-cap, check:pm-widening-tells, check:pm-skill-id-lint, check:doc-authoring, check:platform-checklist, check:self-test-wired, check:nul-bytes, check:pm-governed-prose, check:pm-governed-merges, check:skill-frame-sync.
  • pnpm --filter @objectstack/lint run check:doc-formula-expressions first exited 3 — PREREQUISITE NOT MET (its two packages were unbuilt). That is not a finding; after turbo run build --filter=@objectstack/formula --filter=@objectstack/lint it exits 0, and the merged-head run above is the one recorded.
  • Beyond the derivation, the roster gates whose roster sits under a directory this diff touches were read rather than assumed: check:pm-settings-deny-roster, check-published-list-mirrors.mjs, check-skills-token-ratchet.mjs — all exit 0.
  • Repo-wide pnpm lint is not derived for these paths and is CI's run, not this PR's claim.
  • Collision probe against the in-flight charter PR docs(pm-dispatch): the dev queue is product-only — tooling cards close at first grading, broken gates are deleted, ≤1 tooling dev in flight, tooling is a first-touch label (ruling #202 B) #19462 (branch claude/issue-19457-charter-product-only-queue): git merge-tree --write-tree against its tip exits 0 with a tree and no conflict. That PR's SKILL.md lines were deliberately left untouched — its tooling row goes after finding while the area:* row goes after priority:p0, four rows away; its grading edits sit two lines above the cross-layer insert; its candidate-line edit is the 候选 line while this one rewrites 取卡全序. None of this repo's paths here is merge-driver managed.
  • Check Changeset: this diff publishes nothing — .claude/**, docs/** and scripts/pm/** are outside every package's files[]. It needs the skip-changeset label, which the seat applies (this dispatch writes no labels).

Acceptance notes

  • Noted, not filed: docs/qa/platform-checklist/areas/*.json has no schema and no unknown-top-level-key rule, so axis is accepted by presence alone and a typo (area:studo) would pass every gate. A value check belongs with whichever card next touches the checklist gate; the carrier is named, so it is a note rather than a card.
  • Noted, not filed, 承接者:无 — scripts/pm/ensure-pm-labels.sh is create-if-missing by default, so the eleven new label objects only reach the two repos when someone with label-write credentials runs the script (a PM landing step, exactly as the file says for objectos and hotcrm).

维护者速读(草稿)

改了什么 — 加了一组新标签 area:*(十一个功能轴),给测试清单的十五个 area 文件各加了一个 axis 字段,在北极星的「那条路」下面加了一张「路上的功能点」表(第一条是文档编写那个功能,后面是清单上现在还开着的全部 P0 项,按路步排),并把 PM 章程里「按车道排队」的地方改成「按这张表排队」:domain:* 从此只管哪个席位能动哪些文件。

为什么改 — 您的原话:按功能点划分更容易判断优先级和安排,一个功能点应该从协议一直覆盖到前端,不应该按文件夹划分。以前排队顺序是按文件夹(车道)来的,所以一个功能的三层会被拆到三个队列里各自排;现在顺序只有一份,就是北极星上的那张表,改表即改优先级,不用逐张卡改档位。

风险与代价(含回滚) — 一、十一个轴您已在卡上定了,只改了一个名(API 那一轴由长名简化为 area:api),本轮已在四处改齐:标签行、两个清单文件的 axis、路上的功能点三行。二、新标签只在 objectstack 与 objectui 两个仓建,理由写在脚本里;要不要也给 hotcrm,您随时可加。三、章程的行数棘轮是零余量,所以这次是「加三行、退三行」换来的,退掉的三行内容都在别处有家(PR 正文里逐条列了);还有一行实在付不出,已按卡上要求报了准确数字(要 814,天花板 813),没有抬天花板 —— 您也已裁定保持现状。四、回滚就是 revert 这个 PR,新标签对象留在 GitHub 上不影响任何东西。

席位意见 — (留空,复核席填)

你要做的 — 手动合并这个 PR(Tier H);轴名已定,无需再确认。


Generated by Claude Code

…路」 section as an ordered list of feature points

Step 1 and step 2 of the charter: eleven `area:*` label rows in the PM
label vocabulary (objectstack + objectui), a top-level `axis` field on all
fifteen platform-checklist area files, and a 「路上的功能点」 list under the
North Star's 「唯一的度量,那条路」 seeded with the docs-authoring feature and
the checklist's currently open P0 items, ordered by the road's steps.

Claude-Session: https://claude.ai/code/session_012GcsUbuqFGBibkEDMRC1eE
Co-authored-by: Claude <noreply@anthropic.com>
…e order is the roadmap order, cross-layer feature points file as one parent plus per-layer sub-issues

Step 3 of the charter, paid in place on a ratchet with headroom 0 on every
file: SKILL.md stays at 813 lines and core-rules.md at 151.

Added: the `area:*` glossary row (its four named readers, the roadmap
position that the candidate order reads, and the one-feature-point-per-axis
in-flight cap ride in the row, which the length rule exempts); a line in
域车道 saying `domain:*` decides file ownership and nothing else; and the
cross-layer filing shape in 分诊座位职责.

Paid by retiring three lines whose content has a home elsewhere: the
`packages/lint` exception (the 域车道 table's own devx row and
references/lanes/spec.md 范围), the seat-roster line (全体座位的不变量 plus
座位贴协议), and the multi-lane-only sweep line (多仓协调 carries both
halves).

Claude-Session: https://claude.ai/code/session_012GcsUbuqFGBibkEDMRC1eE
Co-authored-by: Claude <noreply@anthropic.com>
…intainer's one amendment to the eleven

The charter card's axis list was confirmed with a single rename, so the
value is `area:api` in all four places it is spelled: the label row in
scripts/pm/ensure-pm-labels.sh, the `axis` value in the api-backend and
integration-system checklist area files, and the three roadmap lines in
docs/NORTH-STAR.md. The customer capability behind it is unchanged.

The label block's rows are re-padded to the new longest id, and its comment
records the amendment WITHOUT writing the retired spelling: a grep for the
old name must not find a live-looking value, so the maintainer's sentence
is cited on the card's ruling comment rather than quoted here.

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

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 420bd091703ebc91156654b96dcefcc4eb3bfdf8

Isolated at-tier reviewer; reviewed 2026-09-21T03:53Z. (merge-base d00692f5 for both heads; origin/main tip d00692f5 for the whole review, moved to 4045781f at the last re-fetch by two merges touching none of the 19 paths, and git merge-tree --write-tree 4045781f 420bd091 exits 0 with a tree; worktree /home/user/objectstack-review-19488 detached at c55c02ea, then at 420bd091, pnpm install exit 0, removed at the end.)

Premises read in order and nothing else: card #19483 (body, Claim: comment 5754689888, both os-dev-report comments as claims to falsify, ruling comment 5754985448), PR body and file list (both versions), PR comments (zero), docs/NORTH-STAR.md at origin/main. Sequence: c55c02ea was reviewed first in full (every item below was taken on it); the coordinator then named round 2 (420bd091), and the delta was verified separately, then the tree-level and gate readings were re-taken on 420bd091. Every reading below holds on 420bd091 unless it says c55c02ea.

① Derived judgments

  1. Step 1 fidelity. scripts/pm/ensure-pm-labels.sh: eleven gh label create area:* rows inside a two-repo loop (for R in objectstack-ai/objectstack objectstack-ai/objectui; the five-repo loop at line 183 untouched). Ids on c55c02ea are exactly the card's eleven (records access workflow reports identity api-integration files i18n studio ai devpath); on 420bd091 the sixth is area:api, per the maintainer's ruling on the card (comment 5754985448, verbatim 「19483 api-integration 简化成 api 其他同意。」). Descriptions measure 66 to 82 characters and each names the customer capability (e.g. area:access "Permissions that actually hold — RLS/FLS, sharing model, write-path guards"). The two-repo reasoning is in the comment block above the loop (cloud parked, objectos the docs site, hotcrm the exemplar app). pnpm check:pm-label-desc-cap exit 0 on both heads: "38 label descriptions, all ≤100 characters (longest: 100, repo:objectui)". SKILL.md 〈状态模型〉 row at line 121, quoted whole: | area:* | 功能轴:每卡恰一个;分诊首触打,与 domain:* 同笔;工具卡打它所护的轴;⛔ 不回填存量。四读者:维护者按轴看板;定级继承该轴清单项;父单分组;候选顺序,即「功能点位次」= 父单在「路上的功能点」上的次序;同轴至多一个在飞,除非文件面不相交 | — one per card, first touch with domain:*, tooling card carries the axis it protects, no backfill, and all four named readers (board view; grading inherits the axis's checklist item; parent grouping; candidate order) are in the row; git grep -n 'area:' -- .claude/skills/pm-dispatch/SKILL.md reads 3 hits (lines 121, 136, 367). The row is 337 bytes, under the 342 pin, and does not spell the eleven values, so the rename did not touch it. All fifteen docs/qa/platform-checklist/areas/*.json carry a top-level axis; area → axis as read on 420bd091: access-security → access; ai → ai; api-backend → api; approvals → workflow; attachments-storage → files; automation → workflow; cli → devpath; dashboards → reports; i18n → i18n; identity-auth → identity; integration-system → api; platform-core → devpath; records-forms → records; search → records; studio-authoring → studio. Judged against the card's table row by row: every mapping matches (api-backend and integration-system take the renamed value), all eleven values are used, and platform-core carries the card's "the rest" value with its two docs-portal items unexpressed (③). Item ids byte-identical to main: git diff origin/main...HEAD -- docs/qa/platform-checklist/areas | grep -E '^[-+].*"id"' is empty on both heads. pnpm check:platform-checklist exit 0 on both heads ("OK — 15 areas, 264 items (264 active, 0 planned)"). RIGHT.

  2. Step 2 fidelity. docs/NORTH-STAR.md gains one bold-lead paragraph 「路上的功能点」 directly under 「唯一的度量,那条路」 (the only heading-level addition: a diff of the bold-lead paragraphs against origin/main shows exactly that one), followed by an ordered list in the shape 轴 · 功能点 · 清单项 id · 路步. First entry: studio · 管理员在界面里写 Markdown 文档并加到菜单(含 book) · 清单项待写 · P2 = the docs-authoring feature ([Decision] admins author Markdown docs in the console and put them on the app menu — runtime doc/book authoring surface and a doc navigation item (maintainer's stated need) #19482, objectui#10188, both priority:p2, [Decision] admins author Markdown docs in the console and put them on the app menu — runtime doc/book authoring surface and a doc navigation item (maintainer's stated need) #19482's own Path: line reads 缺项 and P2). P0 set re-derived with jq over the fifteen area files: 20 items with "priority": "P0" on 420bd091, the identical 20 on origin/main; all 264 items carry status: active (the only status value present, so status cannot encode a pass); docs/qa/platform-checklist/runs/ holds only README.md and .gitignore, and the README states run records are git-ignored and never committed — so the PR's reading (status is lifecycle, no run record in the tree) is right. The 20 ids cited in the list equal the 20 P0 ids exactly (set diff empty), none missing, none extra. Ordering: monotone in road step, area-grouped inside each step — P2 studio (2); P3 records, access ×6, workflow, api, devpath ×6; P4 api; P5 workflow, api; P6 ai — where the step count takes npm create objectstack as step 1 (the same count [Decision] admins author Markdown docs in the console and put them on the app menu — runtime doc/book authoring surface and a doc navigation item (maintainer's stated need) #19482's Path: line uses). Item 2 of 「优先级」 ends with the appended sentence, verbatim: 「定级读「路上的功能点」:改那张表即改优先级,⛔ 不逐卡改档。」 Items remain numbered 1 to 4 with unchanged text on 1, 3, 4; SKILL.md line 463 still cites 「优先级」第 3 条 and line 362 cites 1、2 条, both pointing at the same items as before. Register: no numbers beyond item ids and road steps, and every other paragraph is byte-identical to main. RIGHT.

  3. Step 3 fidelity. 〈域车道〉 line 243: 「domain:* 只决定文件归属:锚定、热文件串行、单认领路径;⛔ 不是队列或优先级单位。」 〈候选与批次〉 line 464 rewrites 取卡全序 as priority:p0, then pm:blocking, then 功能点位次, then 板上项, then p1, p2, p3, 无级 — 功能点位次 is defined in the glossary row as the parent's position on 「路上的功能点」, and the "at most one feature point per axis in flight unless file surfaces are disjoint" clause lives in that same row (noted: the card places it under step 3, the PR keeps it beside the reader that consumes it; greppable, and ruled A on the card). 〈分诊座位职责〉 line 367: 「跨层功能点(≥2 层)立父单带 area:*+pm:epic+清单项级,逐层子单按 Blocked-by: 排。」 〈Epic 子树车道〉 line 294 now names 跨层功能点(spec/运行时/前端) in the delegation line beside 大开发. 多仓协调 规则 2 line 215: 「跨层功能点或 objectui 消费的 Seam: 卡恒由分诊立父单 + 逐层子单,spec/后端先行。」 references/core-rules.md mirrors each in place: line 58 (跨层功能点 … 逐层子单), line 64 (只决文件归属 ⛔ 非队列非优先级单位), line 66 (area:* 是功能轴,首触打), line 108 (取卡全序 with 功能点位次). references/lanes/*.md: zero edits on both heads. Control re-run myself over the ten lane files: 「车道」 32 hits in 9 of 10 files (the PR says 31; the instrument is live either way); the order vocabulary 队列|全序|取卡|候选顺序|排序|优先序|按域|逐域 hits exactly twice, both about the merge queue (cli.md:17, ui.md:26); a wider sweep (候选/顺序/排队) finds only pointers back to SKILL.md 候选与批次 (services.md:27, spec.md:43) and director-seat lines. No lane charter describes a per-domain queue as the order of work, so under the card's delete-or-re-point instruction zero is the right count. RIGHT.

  4. The ratchet. pnpm check:pm-skill-ratchet exit 0 on both heads: SKILL.md 813 lines (ceiling 813), core-rules.md 151 (ceiling 151), widest SKILL.md table row 342 bytes (pin 342). git diff origin/main...HEAD -- scripts/pm/check-skill-line-ratchet.mjs is empty on both heads: no ceiling entry moved. The three retired lines, each survivor location read and quoted: (a) 「唯一例外 packages/lint 等与 spec 相交的 devx 面…」 survives in the 域车道 table's domain:devx row, line 251 (「packages/lint、scripts/(门禁类)、.github/workflows/(接线)三者按锚定规则例外归 domain:spec」) and in references/lanes/spec.md lines 11 to 12 (「同含围着 spec 契约转的工具链:门禁、生成器、lint 规则…」 / 「一般开发工具面留 devx」); (b) 「座位在编以 label:pm:seat 索引为准…每席恰一张」 survives at line 101 (「一 PM 恰管一车道,一车道由一组座位管,一席一贴」), in 座位贴协议's first line 269 (「贴 = 座位(标签 pm:seat)…」) and in the pm:seat label description ("the label page is the fleet board"); (c) 「sweep 与首触定级只对多车道仓,单车道仓机械三务自理」 survives in 多仓协调 lines 194, 196, 197 (「中央分诊是 domain:*/type/定级的唯一生产者」 / 「单车道仓 repo:* 席自理机械三务」 / 「机械三务 = 自扫 sweep、自打 type、自做 finding 首触定级」). The two moved clauses: 「同级先 Bug 再卡龄」 now on line 466; 「优先非豁免」 is stated by the priority:p0 row on line 120 (「⛔ 不豁免同文件串行、深度等待与认领协议」). The deviation (four readers in the glossary row, not a separate bullet): three lines added and three retired leave 813; a fourth line is 814 against 813; the target bullet is 117 bytes so no fold fits the 120-byte rule; every other ceilinged file reads headroom 0 in the gate's own output. That is a measured ratchet consequence, the card's own instruction for an unpayable line was to report the exact count, which the PR does, and the maintainer ruled A on it (comment 5754985448, question 4). RIGHT.

  5. Collision with PR docs(pm-dispatch): the dev queue is product-only — tooling cards close at first grading, broken gates are deleted, ≤1 tooling dev in flight, tooling is a first-touch label (ruling #202 B) #19462 (tip 36ab00aa, not in origin/main as of 4045781f). git merge-tree --write-tree 36ab00aa c55c02ea exit 0, tree f8e0934f, same tree in the reverse order and from a throwaway bare probe clone with no merge driver registered; git merge-tree --write-tree 36ab00aa 420bd091 exit 0, tree 67708906, probe agrees. Both SKILL.md diffs read side by side and checked line by line against the merged files: every line either PR adds is present in the merged SKILL.md and core-rules.md, and every line either PR removes is absent, for both PRs and on both heads. The two PRs touch different rows and lines: docs(pm-dispatch): the dev queue is product-only — tooling cards close at first grading, broken gates are deleted, ≤1 tooling dev in flight, tooling is a first-touch label (ruling #202 B) #19462's tooling row sits after finding, this PR's area:* row after priority:p0; docs(pm-dispatch): the dev queue is product-only — tooling cards close at first grading, broken gates are deleted, ≤1 tooling dev in flight, tooling is a first-touch label (ruling #202 B) #19462 edits the 候选 line and 舰队 rule, this PR the 取卡全序 line two lines below; docs(pm-dispatch): the dev queue is product-only — tooling cards close at first grading, broken gates are deleted, ≤1 tooling dev in flight, tooling is a first-touch label (ruling #202 B) #19462's grading edits (1–3 条, 「无则关」) sit above this PR's 跨层功能点 insert. Merged SKILL.md is 819 lines, exactly the ceiling docs(pm-dispatch): the dev queue is product-only — tooling cards close at first grading, broken gates are deleted, ≤1 tooling dev in flight, tooling is a first-touch label (ruling #202 B) #19462 raises to in its own edit of the ratchet script (net +6), and this PR is net 0, so the landing order does not matter; merged core-rules.md is 151. ensure-pm-labels.sh merged holds both the tooling row and the eleven area:* rows. No rule of either PR is dropped. RIGHT.

  6. Merge faithfulness. git diff origin/main...420bd091 --name-only is exactly the PR's 19 files (sorted diff against the API file list empty), same on c55c02ea; nothing under packages/**; --stat reads 19 files, +104/−13 on 420bd091 (+98/−13 on c55c02ea), equal to the API's additions and deletions. Round-2 delta git diff --stat c55c02ea 420bd091: exactly the four rename sites (scripts/pm/ensure-pm-labels.sh, areas/api-backend.json, areas/integration-system.json, the three roadmap lines in docs/NORTH-STAR.md); with whitespace ignored the script's hunk is one row rename plus a six-line provenance comment that does not spell the old value, and the other eleven-row re-padding is whitespace only. git grep -n 'api-integration' 420bd091 -- . reads 0 with the control git grep -n 'area:api' 420bd091 -- . reading 2 (comment line 475, label row 512). skip-changeset is right: .claude/**, docs/** and scripts/pm/** sit in no package's files[]; the Check Changeset job reads skipped on 420bd091 because the label short-circuits it by design (pr-automation.yml: "the skip-changeset label — the author's explicit opt-out"). RIGHT.

  7. Gates and CI. (7a) node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derives 37 families on the 19-path diff, and the derived list on 420bd091 is line-identical to the one on c55c02ea. Every family run in the worktree with stdout and stderr redirected to its own log and $? captured before any pipe: 37 of 37 exit 0 on c55c02ea (sweep 2026-09-21T03:31:10Z to 2026-09-21T03:38:29Z) and 37 of 37 exit 0 on 420bd091 (sweep 2026-09-21T03:42:07Z to 2026-09-21T03:47:17Z); --ran with exit codes recorded reconciles 37 derived / 37 run / 0 NOT-MEASURED / 0 UNRUN on both heads, the zero reported as DERIVED. check:doc-formula-expressions was run after a turbo build of @objectstack/formula and @objectstack/lint (build exit 0), matching the PR's prerequisite note. The three roster gates the PR names beyond the derivation (check:pm-settings-deny-roster, check-published-list-mirrors.mjs, check-skills-token-ratchet.mjs) exit 0 on both heads. Docs gates that read docs/NORTH-STAR.md: check:doc-authoring exit 0, check:skill-frame-sync exit 0, check:pm-governed-prose exit 0. The dev's 37/37 is not falsified. RIGHT. (7b) CI on 420bd091 at the last poll 2026-09-21T03:47Z, check-runs paginated (38): TypeScript Type Check success; Test Core success with all six shards success; Dogfood Regression Gate success; Build Core skipped and Temporal Conformance (live PG + MySQL) skipped (paths filter; no trigger for this diff); Governed Surface Queue Guard success; Lint & Repo Gates in_progress. No failure on the head. On c55c02ea the Lint & Repo Gates run ended cancelled at 2026-09-21T03:35:36Z — lint.yml concurrency.cancel-in-progress: true fired on the round-2 push at its step 36, after steps 31 to 35 (PM skill line ratchet, PM skill issue-ID lint, PM label description cap, dispatch-gates self-test, watch-hint literals) had completed success; that is a superseded run, not a red. One required context is not terminal on the head. NOT MEASURED (Lint & Repo Gates on 420bd091; the landing seat reads it green before the hand-merge).

② Semver level

None: nothing publishes. All 19 paths are .claude/skills/pm-dispatch/**, docs/NORTH-STAR.md, docs/qa/platform-checklist/areas/*.json and scripts/pm/ensure-pm-labels.sh, none inside any released package's files[]; no .changeset/*.md is added; Clause-②: no and the skip-changeset label are consistent with that.

③ Boundary flags

  • platform-core's two docs-portal items. Confirmed: platform-core.docs-audience-gate and platform-core.docs-portal-render are both P1, active, in platform-core.json, whose file-level axis is devpath; the card's table sends them to studio, which a per-file field cannot express. Ruled A on the card (leave it; a per-item axis is a later card). Until then, grading inheritance for those two items reads devpath.
  • Label objects in two repos, not five. Confirmed by the loop line (objectstack + objectui) against the untouched five-repo loop at line 183; reasoning in the file; ruled A on the card.
  • Acceptance note, unknown-key check. Confirmed: scripts/check-platform-checklist.mjs has no top-level-key rule and no axis value check (grep for either reads nothing), so axis is accepted by presence and any spelling passes the gate; the round-2 rename was guarded only by the grep. Carrier named (the next card touching that gate).
  • Acceptance note, label objects reach GitHub only when the script runs. Confirmed from the script header (create-if-missing default, --reconcile the deliberate action); this review did not run it.
  • Outside the claim's declared surface, for the maintainer's pruning of the table: the tree carries no run record, but the qa-run issues do — QA run · priority:P0 · e4e5c6e3 · 2026-08-17 · 7 PASS / 7 PARTIAL / 2 FAIL / 2 BLOCKED #9334 (priority:P0 scope at e4e5c6e3) records 7 pass, 7 partial, 2 fail, 2 blocked over the 18 P0 items of that day, all against older item revisions and a build several weeks stale. The PR's "all twenty are open" is the conservative reading of the card's words and is right for a first table; which of the twenty the maintainer strikes as already passing is the table's own first edit, not this PR's.
  • First entry has no checklist item. 清单项待写 is honest, and the README's planned status exists for exactly this gap; until an item is appended, the docs-authoring feature point inherits nothing through reader (ii). Not a defect of this PR; a note for whoever files the feature's parent card.
  • PR body. Round 2 left the body to the seat (the dev's role file forbids a body PATCH); the seat's edit replaced the three stale paragraphs as the report prescribed, and the body's footer now reads the bare form rather than the session-URL form (a channel effect on edit; durable attribution stays in the body prose and the card's Claim:). No governed-surface consequence; noted so nobody "repairs" it.
  • Nothing else outside the claimed surface: no packages/**, no ADR, no AGENTS.md, no lane file, no hook.

Implemented-by: claude/issue-19483-feature-axis-charter
Reviewed-by: session_012GcsUbuqFGBibkEDMRC1eE

VERDICT: PASS — Tier H (docs/NORTH-STAR.md + .claude/**); this record is not the landing record for Tier H: the maintainer merges by hand, after Lint & Repo Gates on 420bd091 reads success.


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

Provenance — director seat, summon #25 (session_012GcsUbuqFGBibkEDMRC1eE), 2026-09-21T03:57Z


Generated by Claude Code

… list — every checklist item belongs to exactly one feature point

The maintainer read the first version and said it looked like a handful of
issues rather than the platform's feature list. It was: one card plus the
checklist's currently-failing P0 items.

This rewrites the section as the whole feature map. Six blocks, one per step
of the road the North Star already measures, and inside each block one line
per feature point at capability level — a customer-visible capability that
runs from the protocol through the runtime to the frontend. The end-user
capabilities (records, access, workflow, reports, identity, files, i18n) sit
at the step where the road first needs them, which is where the app is first
run and seen.

The completeness claim is mechanical, not editorial: the feature points are
derived by grouping every item in docs/qa/platform-checklist/areas/*.json so
that each item belongs to exactly one line — 264 items on disk, 264 mapped,
zero unmapped, zero double-mapped, zero ids the ledger does not have. The
per-item listing is on the card.

The 路步 column is gone (the block position is the step), the docs-authoring
feature keeps its 「清单项待写」 slot, and the page's own rules hold: no
counts, no pass/fail status, no new headings, and the ledger is still not
copied here.

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

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 16418377774926fc3602f6a5649811557e24f21a

Isolated at-tier reviewer, round 3; reviewed 2026-09-21T04:37Z. Head 420bd091 was reviewed in full at comment 5755154226 (PASS); this record judges the round-3 delta on top of it and re-reads CI on the new head. Shape as ruled on #19491 R5: the diff and the card were read, PR checks were taken from the head's check-runs over REST, and no derived gate family was re-run locally (the unchanged 18 files carry 5755154226's 37/37 sweep, and CI runs them on this head). Worktree /home/user/objectstack-review-19488-r3 detached at origin/main (2cac3636, tip 48c39e00 at the last re-fetch, merge-base d00692f5 unchanged), the PR branch fetched into it, removed at the end. git merge-tree --write-tree origin/main 1641837777 exits 0 with a tree; no commit on main since the merge-base touches docs/NORTH-STAR.md or docs/qa/platform-checklist/areas/.

Premises: the maintainer's words on the card, verbatim, 「19488 路上的功能点写的很奇怪,真的是平台总体的功能清单吗?怎么感觉是几个issue」; the dev's round-3 os-dev-report on #19483 (comment 5755372570), whose listing was used only to cross-check numbers derived here; the PR (draft, auto_merge null, labels documentation size/m skip-changeset, 19 files, +176/−13 per the API, equal to git diff --shortstat d00692f5 1641837777).

① Derived judgments

  1. Delta scope. git log --oneline 420bd091..1641837777 is one commit; git diff --name-status 420bd091 1641837777 is exactly M docs/NORTH-STAR.md (+95/−23, one hunk). The hunk's context lines are the blank line under 「唯一的度量,那条路」 and the first two lines of 「优先级」, so everything outside the 「路上的功能点」 section — the 「唯一的度量」 paragraph, all four 「优先级」 items, 「阶段姿态」, 「仪器为车队服务」, 「现在不做」, 「账本」 — is byte-identical to 420bd091. RIGHT.

  2. Shape against the ask. Six bold step lines ①–⑥ (npm create objectstack 起项目,写元数据 / 本地跑起来、看到 / 验证 / 发布并装进一个环境 / 接一个 Agent / 按客户一句话需求迭代一次), one per arrow-step of the 「唯一的度量,那条路」 sentence, with the departure point folded into ①. Bold paragraphs, not headings: grep -n '^##' docs/NORTH-STAR.md reads nothing on the head (the page still has its single # title). 76 feature-point lines, distributed ① 8 / ② 45 / ③ 6 / ④ 8 / ⑤ 6 / ⑥ 3; every one is a capability sentence in business language, none is a bare area name, and none is an issue-shaped to-do. The old 路步 column is gone (block position is the step). The docs-authoring entry keeps 清单项待写 at ① (line 24). RIGHT.

  3. Completeness, re-derived. Ids on disk at the head: .items[].id over the fifteen docs/qa/platform-checklist/areas/*.json = 264 (access-security 27, ai 8, api-backend 23, approvals 18, attachments-storage 9, automation 16, cli 17, dashboards 11, i18n 5, identity-auth 22, integration-system 18, platform-core 29, records-forms 39, search 7, studio-authoring 15), all spelled area.slug, no slug repeated across two files. Ids named on the 76 lines, a bare id resolved against the line's first-listed 清单区 and a dotted id taken whole: 264 id tokens, 264 distinct — mapped 264 / unmapped 0 / double-mapped 0 / unknown 0 (set difference in both directions empty; no full id appears on two lines, no id appears twice on one line). The dev's totals (264 / 0 / 0 / 0 / 76) are reproduced, not adopted. RIGHT.

  4. Line format. All 76 lines split on · into exactly four fields 轴 · 功能点 · 清单区 · 项 id. 轴 values used: devpath 17, studio 8, records 10, access 8, identity 7, workflow 6, reports 3, files 2, i18n 2, api 8, ai 5 — all eleven from the area:* register and no other. (Correction to the brief's wording: the PR's SKILL.md area:* row at line 121 deliberately does not spell the eleven values — the register is the eleven gh label create area:* rows in scripts/pm/ensure-pm-labels.sh at the head: records access workflow reports identity api files i18n studio ai devpath.) 清单区 values are all real area files; 10 lines name two or three (A + B), and in every one the bare ids resolve in the first-listed area and every dotted id names a non-first area on that same line (no dotted id is redundantly prefixed, none names an area the line does not list). No digit anywhere in the section except the i18n name; the only numerals are the step glyphs ①–⑥, which are ordinals not counts; no pass/fail or status word on any line. RIGHT.

  5. Single-id lines. Eleven lines own exactly one checklist id: FP-02 cli.build-own-contract, FP-03 cli.hook-body-extraction-gates, FP-12 platform-core.settings-hub-roundtrip, FP-59 studio-authoring.metadata-diagnostics-sweep, FP-60 cli.plugin-manifest-build-contract, FP-67 studio-authoring.packaged-display-class-direct-edit, FP-68 ai.agent-tool-skill-metadata-roundtrip, FP-71 ai.skill-instructions-mcp-prompts, FP-73 identity-auth.api-key-ui-lifecycle, FP-74 studio-authoring.first-run-loop, FP-76 cli.dev-automigrate-policy. Each is worded as a capability (打成插件 / 给 Agent 一把个人密钥 / 平台设置在界面里改 / …), not as the item's title, and the 1:1 is a fact about how many items the ledger has for that capability, not an item promoted to a feature point. Read as "no line IS a single item": RIGHT, with the eleven named so the maintainer can merge any he reads as too thin.

  6. Business-language fidelity. All 76 lines were read against their items' titles (not a 15-line sample). 74 describe their items faithfully — e.g. FP-04 (object designer + live view authoring + record page ↔ 不写代码建对象、字段、列表、表单与记录页), FP-06, FP-09, FP-14–FP-22, FP-23–FP-29, FP-31–FP-35, FP-36–FP-40, FP-41–FP-43, FP-44–FP-45, FP-47–FP-49, FP-51–FP-53, FP-54–FP-58, FP-61–FP-63, FP-65–FP-66, FP-69–FP-70, FP-72, FP-75–FP-76 — no line claims a capability its items do not test, and the expected-fail arms inside some items (keyboard accelerators, seed replace, the default build's silent fallback) are not overclaimed because the map carries no status. Two lines are flagged: FP-50 (line 69, api · REST 面的构造契约:开关决定挂什么;公式与计时也归同一份契约管) owns api-backend.formula-gates and api-backend.formula-stdlib-matrix, which are the CEL formula engine (27 stdlib functions give known answers, date arithmetic fails at build) — not the RestServerConfig construction contract the line names, so 「公式…也归同一份契约管」 misdescribes those two; the capability is present and findable by 公式 but belongs on its own line (公式算得对) or with records. WRONG on that one line — a one-line reword, not a hole in the map. FP-64 (line 89) glues platform-core.lifecycle-retention-sweep (ADR-0057 telemetry retention reaping) onto the packaged-object/activation-ledger line with 「过期数据按保留期回收」 — accurate words, wrong feature point (retention is not a packaging capability): debatable, named for the maintainer's pruning. Under-described but not misdescribed: FP-11 does not name home-admin-cluster-links, console-installability-indicators, app-management-toggle (all shell); FP-29's platform-owner-email-anchor rides under 平台管理员身份本身挡得住. Overall: RIGHT with FP-50 to reword.

  7. The page's own rules. 「本页不带任何数字;数字从命令来」: no count, total, percentage or status on the page; the section's ids are pointers, as the old section's 清单项 id column was. 「能力与验证的账本是 docs/qa/platform-checklist/,本页不复制它」: the section carries ids only — no titles, steps, priorities or status — so it indexes the ledger, it does not copy it. 「优先级」 item 2 still ends 「定级读「路上的功能点」:改那张表即改优先级,⛔ 不逐卡改档。」 verbatim and the sentence reads right against the new table: a card's feature point is a line, its step is the block, and 优先级 1–2 plus the 唯一的度量 rule (第一个断掉的步骤是 P0;跑得通但结果错的是 P2) give the grade. Items 1, 3, 4 unchanged. RIGHT.

  8. The two judgment placements. (a) studio-authoring.first-run-loop at ⑥ rather than ①: the item pins package → object → record → app → publish → end-user, which is exactly what ⑥ 「按客户一句话需求迭代一次」 names, while ① already lists the authoring capabilities one by one — defensible; not wrong. (b) platform-core.docs-audience-gate and platform-core.docs-portal-render owned by the studio docs line while platform-core.json's file-level axis stays devpath: the card ruled A on that split (per-item axis is a later card), and the map is now the place that expresses it — not wrong. The consequence is general, not specific to those two: eight lines own at least one item whose area file carries a different axis than the line (FP-08 studio←platform-core; FP-51 api←automation; FP-52 api←cli; FP-53 api←platform-core; FP-61 devpath←api-backend; FP-64 devpath←access-security; FP-65 workflow←api-backend, access-security; FP-66 access←studio-authoring). That is the 「一个功能点从协议到运行时到前端是一整条」 rule doing its job, and SKILL.md reader (ii) 「定级继承该轴清单项」 resolves through the file axis for those items until the per-item axis exists — recorded under ③. RIGHT.

  9. Reproducibility of the bare-id rule. 「id 不带前缀时属于它前面那个清单区,跨区的写全名」 is unambiguous on the 66 single-area lines; on the 10 multi-area lines it does not say which listed area takes the bare ids (in all 10 it is the first-listed, and any other reading yields an id the ledger does not have, so a wrong reading is self-detecting but not self-explaining). Wording nit, one clause (「列在第一个的清单区」); does not affect the mapping. RIGHT, nit named.

  10. CI on the head — read over REST from /commits/1641837777…/check-runs (38 runs) at 2026-09-21T04:34Z: TypeScript Type Check success; Test Core success (rollup, and all six shards success); Dogfood Regression Gate success (the rollup; the three matrix shards skipped by the paths filter); Build Core skipped (paths filter); Temporal Conformance (live PG + MySQL) skipped (paths filter); Governed Surface Queue Guard success; Lint & Repo Gates in_progress — NOT MEASURED, named, non-blocking for the content verdict; the landing seat reads it green before the hand-merge. No failure on the head. A second Part-of PR must not also close its card run (not a required context) was in progress beside its earlier success.

② Semver level

None: the round-3 delta is one file under docs/**, outside every released package's files[]; the PR's Clause-②: no and skip-changeset still hold (unchanged from 5755154226 ②). Carriers: none hung — the delta adds no rule, gate, hook or skill text; the completeness proof is a one-off listing, and its carrier (below) is named, not left implicit.

③ Boundary flags

  • Completeness is proved once, not gated. Nothing in the tree re-checks 「每一项都恰好属于这里的一行」; an item appended to the checklist tomorrow silently belongs to no feature point, and an id rename breaks a reference on this page. The dev names the carrier (the next card touching scripts/check-platform-checklist.mjs); agreed, and deliberately not a script this round per the dispatch.
  • The step count moved from seven to six. The old table counted npm create objectstack as step 1 (docs-authoring P2, records P3, … ai P6); the map folds it into ① so every 路步 is one lower. No script in scripts/pm/ parses the P step of a card's Path: line (grep reads nothing), and SKILL.md line 362's Path: format is unchanged; but [Decision] admins author Markdown docs in the console and put them on the app menu — runtime doc/book authoring surface and a doc navigation item (maintainer's stated need) #19482's own Path: line reads P2 on the old count and its feature point now sits at ①. Carrier: the triage seat, next touch of [Decision] admins author Markdown docs in the console and put them on the app menu — runtime doc/book authoring surface and a doc navigation item (maintainer's stated need) #19482 (and any card that wrote a 路步 before this lands). Not this PR's file.
  • Axis inheritance vs map ownership (①.8): eight lines own items whose file axis differs from the line's 轴; reader (ii) inherits by file axis until the ruled-A per-item axis card exists. Not a defect of this PR; the ruling's known residue.
  • FP-50 (①.6): the two formula items ride under the REST construction-contract line; reword or split before or after the hand-merge — the maintainer's table edit either way.
  • PR body: the dev again did not PATCH it (role-file clause, stated in the report) and left the paste-ready replacement for the seat; read over REST, the body already carries that section (「The roadmap section, rewritten in round 3」 in place of the old 「Step 2」 block, with the 264 / 76 totals) — the seat’s write is done. No governed-surface consequence.
  • Nothing else outside the claimed surface: no packages/**, no ADR, no AGENTS.md, no .claude/** change this round.

Implemented-by: claude/issue-19483-feature-axis-charter
Reviewed-by: session_012GcsUbuqFGBibkEDMRC1eE

VERDICT: PASS — Tier H (docs/NORTH-STAR.md + .claude/**); this record is not the landing record for Tier H: the maintainer merges by hand, after Lint & Repo Gates on 1641837777 reads success. FP-50 is the one line to reword.


Generated by Claude Code

…tention leaves the packaged-object line

Two lines the round-3 review judged wrong about what they describe, fixed in
the map rather than in the prose alone.

The CEL formula items pin the formula engine — the stdlib's registered
functions answering known values against the built package, and
date-arithmetic failing at build time — not RestServerConfig's construction
contract, so they get their own line and the REST line drops 公式. 计时 stays
there because the Server-Timing item really does sit on it, beside the verb
gate.

The ADR-0057 lifecycle sweep is telemetry retention, not packaged-artifact
governance; it moves to its own ops line in the step where the app is running
and off the packaged-object / activation-ledger line, whose wording loses the
clause with it.

Nothing else in the section moved: every one of the checklist's items is
still on exactly one line, four fields per line, no digits, no new headings.

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

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 410c37f7108c69c44601771e6ab2d6477e054a4e

Isolated at-tier reviewer, round 4; reviewed 2026-09-21T04:58Z. Head 1641837777 was reviewed in full at comment 5755471665 (PASS, two lines flagged); this record judges the round-4 delta on top of it and re-reads CI on the new head. Same shape as ruled on #19491 R5: diff and card read, PR checks taken from the head's check-runs over REST, no derived gate family re-run locally (the 18 unchanged files carry 5755154226's 37/37 sweep; CI runs them on this head). Fresh worktree /home/user/objectstack-review-19488-r4 detached at origin/main (tip a227afa415 at the time of the review — past the 48c39e00 the coordinator named — merge-base d00692f5 unchanged), the PR branch fetched into it, removed at the end.

Premises: the round-3 record 5755471665 and the two lines it flagged (FP-50 formula pair under the REST construction-contract line; FP-64 retention sweep glued to the packaged-object line); the dev's round-4 os-dev-report on #19483 (comment 5755588689), whose totals were used only to cross-check numbers derived here; the PR over REST (draft, auto_merge null, labels documentation size/m skip-changeset, 19 files, +178/−13, mergeable true / mergeable_state blocked as a draft is).

① Derived judgments

  1. Delta scope. git log --oneline 1641837777..410c37f7 is one commit (docs(north-star): the formula engine is its own feature point, and retention leaves the packaged-object line). git diff --name-status 1641837777 410c37f7 is exactly M docs/NORTH-STAR.md; --stat reads +4/−2; three hunks at old lines 29, 66 and 86, all inside 「路上的功能点」 (which spans lines 13–107 on 1641837777): one added line in the ② devpath run, one reworded plus one added line in the ② api run, one reworded line in the ④ devpath run. Every context line is a neighbouring feature-point line; the intro paragraph, the six step lines, 「唯一的度量」, 「优先级」 and everything after are byte-identical to 1641837777. Exactly what the coordinator named, nothing else. RIGHT.

  2. Completeness, re-derived on 410c37f7. Ids on disk: .items[].id over the fifteen docs/qa/platform-checklist/areas/*.json = 264 (the area files are untouched this round — same per-file counts as 5755471665 ①.3). Ids named on the feature-point lines (bare id → the line's first-listed 清单区, dotted id whole): 264 tokens, 264 distinct → mapped 264 / unmapped 0 / double-mapped 0 / unknown 0; set difference empty in both directions. 78 feature points (76 + 2 new lines), distributed ① 8 / ② 47 / ③ 6 / ④ 8 / ⑤ 6 / ⑥ 3. The dev's 264 / 0 / 0 / 0 / 78 is reproduced, not adopted. RIGHT.

  3. Invariants. All 78 lines split on · into exactly four fields; 轴 values devpath 18, studio 8, records 10, access 8, identity 7, workflow 6, reports 3, files 2, i18n 2, api 9, ai 5 — all from the eleven-value area:* register in scripts/pm/ensure-pm-labels.sh, no other value; every 清单区 a real area file; the ten multi-area lines unchanged, bare ids still resolve in the first-listed area, no dotted id redundantly prefixed. No digit in the section except the name i18n; grep -n '^##' docs/NORTH-STAR.md reads nothing; no count, status or pass/fail word. Single-id lines are now twelve (the eleven from 5755471665 ①.5 plus the new retention line) — each a capability sentence, none an item title. 「优先级」 unchanged, 「本页不带任何数字」 and 「本页不复制它」 hold. RIGHT.

  4. The four lines against their items' titles.

    • New, line 32 devpath · 遥测与生命周期数据按保留期回收,声明了归档的对象绝不热删 · platform-core · lifecycle-retention-sweep — the item (ADR-0057 sweep: backdated telemetry rows past retention reaped bounded on the hourly sweep, onlyWhen spares live rows, an archive-declaring object is never hot-deleted unarchived, OS_LIFECYCLE_DISABLED=1 disarms) is described faithfully in both clauses; ② beside the other platform-core boot-time capabilities is the right step (it runs on a stock boot). RIGHT.
    • Reworded, line 70 api · REST 面的构造契约:开关决定挂什么、哪些动词准过,计时只对管理员开 — six items: the three RestServerConfig.* construction contracts and the all-tombstone routes block (开关决定挂什么), api-methods-verb-gate (哪些动词准过), server-timing-admin-gated (计时只对管理员开). Every clause now names an item it owns; the formula clause is gone. RIGHT — the FP-50 flag is closed.
    • New, line 71 api · 公式引擎:标准库函数逐个给出已知答案,写错的表达式在构建时就被挡下 · api-backend · formula-stdlib-matrix, formula-gates — formula-stdlib-matrix (all 27 registered CEL functions give known answers against the built package) ↔ 标准库函数逐个给出已知答案, exact; formula-gates ("formula runtime fixes hold and date-arithmetic fails at build time") ↔ 写错的表达式在构建时就被挡下 — the item's build-time arm is date arithmetic specifically, so the clause generalises one arm to the capability; that is the capability-level wording the map asks for, not an overclaim (noted, not flagged). Placed directly under the REST line at ②, where the api run sits. RIGHT.
    • Reworded, line 91 devpath · 随包发来的对象只能扩不能改,启停逐条记在激活台账上 · platform-core + access-security · packaged-object-extend-only, activation-ledger-registration-home, activation-ledger-row-contract, access-security.activation-write-operator-gate — the retention clause and its id are gone; the four remaining items (extend-only Regime E; the ledger's registration home; the row contract; the write-operator gate) are all "packaged objects and their activation ledger". RIGHT — the FP-64 flag is closed.
  5. Origin/main moved. origin/main tip a227afa415 (past 48c39e00, which carries docs(pm-dispatch): the dev queue is product-only — tooling cards close at first grading, broken gates are deleted, ≤1 tooling dev in flight, tooling is a first-touch label (ruling #202 B) #19462 as 733f42d6: SKILL.md ceiling 819, tooling rows in ensure-pm-labels.sh). git log 48c39e00..origin/main -- .claude/skills/pm-dispatch docs/NORTH-STAR.md docs/qa/platform-checklist/areas scripts/pm/ensure-pm-labels.sh is empty, and nothing on main since the merge-base touches docs/NORTH-STAR.md or the area files. git merge-tree --write-tree origin/main 410c37f7 exits 0 with tree d429aebf (clean, no conflict). In that tree: .claude/skills/pm-dispatch/SKILL.md is 819 lines = the landed ceiling (['.claude/skills/pm-dispatch/SKILL.md', 819] in scripts/pm/check-skill-line-ratchet.mjs on origin/main; origin/main's own SKILL.md is 819, this PR is net 0 on it); references/core-rules.md 151 = its ceiling; ensure-pm-labels.sh holds both docs(pm-dispatch): the dev queue is product-only — tooling cards close at first grading, broken gates are deleted, ≤1 tooling dev in flight, tooling is a first-touch label (ruling #202 B) #19462's tooling rows and the eleven area:* rows; the merged area files still carry 264 ids, so the map's completeness survives the merge. RIGHT.

  6. CI on the head — read over REST from /commits/410c37f7…/check-runs (36 runs) at 2026-09-21T04:57Z, about two minutes after the push: Dogfood Regression Gate success (rollup; the three matrix shards skipped by the paths filter); Build Core skipped (paths filter); Temporal Conformance (live PG + MySQL) skipped (paths filter); Governed Surface Queue Guard success; TypeScript Type Check in_progress (its four Type Check · legs running, the rollup not yet reported) — NOT MEASURED; Test Core in_progress (shards 5/6 and 6/6 success, four shards running) — NOT MEASURED; Lint & Repo Gates in_progress — NOT MEASURED. No conclusion other than success or skipped on any of the 36 runs. The three named contexts are non-blocking for this content verdict; the landing seat reads them green before the hand-merge.

② Semver level

None: the round-4 delta is one file under docs/**, outside every released package's files[]; Clause-②: no and skip-changeset still hold (unchanged from 5755154226 ②). Carriers: none hung — the delta adds no rule, gate, hook or skill text.

③ Boundary flags

  • Both round-3 flags (FP-50, FP-64) are closed by this delta; no new line is flagged.
  • Standing from 5755471665, unchanged and not this PR's file: the completeness proof is a one-off listing (carrier: the next card touching scripts/check-platform-checklist.mjs); the road's step count moved from seven to six so [Decision] admins author Markdown docs in the console and put them on the app menu — runtime doc/book authoring surface and a doc navigation item (maintainer's stated need) #19482's Path: line reads P2 on the old count (carrier: triage seat on next touch); eight lines own items whose area-file axis differs from the line's 轴 (the ruled-A per-item-axis residue); the bare-id rule's wording on multi-area lines is a one-clause nit.
  • PR body: read over REST, it carries the seat's round-3 roadmap section; whether the seat updates its totals from 76 to 78 feature points is the seat's write, not a content defect.
  • Nothing else outside the claimed surface: no packages/**, no ADR, no AGENTS.md, no .claude/** change this round.

Implemented-by: claude/issue-19483-feature-axis-charter
Reviewed-by: session_012GcsUbuqFGBibkEDMRC1eE

VERDICT: PASS — Tier H (docs/NORTH-STAR.md + .claude/**); this record is not the landing record for Tier H: the maintainer merges by hand, after TypeScript Type Check, Test Core and Lint & Repo Gates on 410c37f7 read success.


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

Provenance — director seat, summon #25 (session_012GcsUbuqFGBibkEDMRC1eE), 2026-09-21T04:59Z


Generated by Claude Code

Two conflicts, both at the 取卡全序 lines in the pm-dispatch charter, and
both sides are the maintainer's: main's newly ruled tiers (直派插队卡 and
契约面卡 ahead of the label ladder) and this branch's roadmap position inside
the ladder. Resolved by composing them rather than choosing — main's order
line verbatim, and main's ladder line with 功能点位次 inserted after
`pm:blocking`, which is exactly where this branch's own line had it.

⚠️ One deviation from the prescribed wording, because the prescribed line
cannot land: composing into main's ladder line, tie-break clause included,
measures 134 bytes against the 120-byte per-line rule that
check:pm-skill-ratchet enforces on these files, so the gate would go red.
The tie-break stays on the following line instead, where this branch already
carried it — every rule is stated exactly once, nothing is duplicated, and
the ladder line lands at 108 bytes. In core-rules.md, which has no such
following line, the summary loses that tie-break clause; the full rule stays
in SKILL.md, which is what that file's own header prescribes.

Everything else takes main's side, and nothing else of this branch changes.

Claude-Session: https://claude.ai/code/session_012GcsUbuqFGBibkEDMRC1eE
Co-Authored-By: Claude <noreply@anthropic.com>

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: e58fc6b2eb22659d48abfb55a66a4dd2e30f4a24

Isolated at-tier reviewer, round 5; reviewed 2026-09-21T05:29Z. Head 410c37f7 was reviewed in full at comment 5755610118 (PASS); this record judges the round-5 merge on top of it — one merge commit, e58fc6b2 = Merge origin/main (ea64bbc6) into the branch, parents 410c37f7 and ea64bbc6, no rebase (git log --first-parent 410c37f7..e58fc6b2 is that one commit) — and re-reads CI on the new head. Same shape as ruled on #19491 R5: diff and card read, PR checks from the head's check-runs over REST, no derived gate family re-run locally except the one named in ①.5, which the merge itself is about. Fresh worktree /home/user/objectstack-review-19488-r5 at origin/main, the PR branch fetched, the head checked out detached for ①.5, removed at the end. origin/main tip was 8fc6a5f6 at the freshest fetch (three commits past ea64bbc6: #19453, #19445, #19378 — none touching the PR's 19 paths); merge-base of origin/main and the head is ea64bbc6.

Premises: the round-4 record 5755610118; the dev's round-5 os-dev-report on #19483 (comment 5755798197), used to cross-check readings derived here; the PR over REST (draft, auto_merge null, labels documentation size/m skip-changeset, 19 files, +178/−13).

① Derived judgments

  1. The merge adds nothing beyond main except the two composed lines. Three readings, all on the worktree. (i) git merge-tree --write-tree ea64bbc6 410c37f7 — the AUTOMATIC merge of the two parents — exits 1 with exactly two content conflicts (.claude/skills/pm-dispatch/SKILL.md, .claude/skills/pm-dispatch/references/core-rules.md; scripts/pm/ensure-pm-labels.sh auto-merges), tree 14e9a4b4. git diff 14e9a4b4 e58fc6b2 — everything the dev did by hand on top of the automatic merge — touches only those two files, 2 insertions / 10 deletions: in each file the five conflict lines (the two markers, the separator, main's ladder line, the PR's old order line) are replaced by one composed ladder line, with main's order line kept as the context line above it. Nothing else differs from the automatic merge. (ii) git diff --name-only 410c37f7 e58fc6b2 (the head against its PR-side parent) is 57 files, and as a set it equals git diff --name-only d00692f5 ea64bbc6 (main's own range since the old merge-base) — set difference empty both ways, so the first-parent side received main's content and nothing that is not main's. (iii) git diff --name-only origin/main...e58fc6b2 is exactly the PR's 19 files, equal to git diff --name-only e58fc6b2^2 e58fc6b2 (the head against ea64bbc6, which is the three-dot base by definition), and the API's changed_files reads 19; against the fresher origin/main tip a two-dot diff adds the seven files those three later commits changed, none in the 19. Of the 19: sixteen (docs/NORTH-STAR.md, the fifteen area files) are byte-identical to 410c37f7 — so 「路上的功能点」 is byte-identical to the round-4 head, 264 / 264 / 0 / 0 / 0 over 78 lines carries over unchanged; ensure-pm-labels.sh differs from 410c37f7 only by main's docs(pm-dispatch): the dev queue is product-only — tooling cards close at first grading, broken gates are deleted, ≤1 tooling dev in flight, tooling is a first-touch label (ruling #202 B) #19462 tooling rows, and its PR-side +/− lines are identical before and after the merge; the two charter files are judged in ①.2. RIGHT.

  2. The composed lines, quoted from the head. SKILL.md 472–473 and core-rules.md 108–109, identical in both files, byte for byte:
    「- 取卡全序:维护者直派插队卡(出处三件)> 契约面卡(判据见 references/lanes/spec.md)> 标签序。」
    「- 标签序:priority:p0 > pm:blocking > 功能点位次 > target: 板上项 > p1 > p2 > p3 > 无级。」
    The order line is main's verbatim (docs(pm-dispatch): enter the maintainer's 插队 and 契约面卡 tiers into the 取卡全序 (SKILL.md + core-rules twin) #19506); the ladder is main's with 功能点位次 inserted after pm:blocking, where the PR's own pre-merge line (priority:p0 > pm:blocking > 功能点位次 > 板上项 > …) had it; both sides are the maintainer's and neither is dropped. The tie-break 「同级先 Bug 再卡龄」: grep -c over SKILL.md at the head reads 1 — on line 475 「全序每级现读/现算,零逐卡维护;同级先 Bug 再卡龄;无级/缺 Path: 轮报记分诊缺口。」, the PR's own line since round 1 — not twice (main had carried it on the ladder line; the composed ladder line omits it because line 475 already holds it; composing it into the ladder would be 134 bytes against the 120-byte cap). core-rules.md carries no tie-break at all now (main's summary line had 「同级先 Bug 再卡龄」, the PR's had 「同级先缺陷卡」; the composed line has neither): the file's own header reads 「细节以 SKILL.md 与其它 references 为准,⛔ 不新增规则」, so the summary defers by design — option A, accepted by the coordinator; recorded under ③. git grep -n 取卡全序 e58fc6b2 -- .: the composed line in both charter files, the pre-existing runbook heading 「## 车道取卡全序与 pm:blocking」, and comment text in scripts/pm/check-half-states.mjs; the old spelling 「取卡全序:priority:p0…」 reads 0 hits. RIGHT.

  3. The PR's own sentences against the tiered order. With 直派插队卡 and 契约面卡 above the 标签序, 功能点位次 is one rung inside the ladder (below priority:p0 and pm:blocking, above target: 板上项). Every sentence this PR adds was re-read at the head against that: the area:* glossary row (line 122) names 功能点位次 as the fourth reader — 「候选顺序,即「功能点位次」= 父单在「路上的功能点」上的次序」 — which names the reader and defines the rank, not the whole order, and it stood in exactly that relation to the PR's own pre-merge ladder (where 功能点位次 was already third); line 471 「取卡前置 = 北极星「优先级」第 3 条」 is a precondition, not an order; line 475 「全序每级现读/现算,零逐卡维护」 holds for the two new tiers too (出处三件 is read off the card, the 契约面 criterion is computed from lanes/spec.md); line 372 「跨层功能点(≥2 层)立父单带 area:*+pm:epic+清单项级」 and core-rules 58 / 64 / 66 say nothing about queue order; NORTH-STAR 「优先级」 item 2 「定级读「路上的功能点」」 is grading, not queue order. No sentence of the PR's says 功能点位次 is the first or the whole order; none contradicts the tiered line above it. The 〈候选与批次〉 rules (lines 433–465) are main's text untouched by this PR and read the same. RIGHT.

  4. Three-dot surface unchanged. 19 files, the same nineteen as every earlier round (two charter files, NORTH-STAR.md, fifteen area files, ensure-pm-labels.sh); nothing under packages/**, no ADR, no AGENTS.md, no lane file, no hook. The API's +178/−13 equals round 4's. RIGHT.

  5. Ratchet at the head (node scripts/pm/check-skill-line-ratchet.mjs with e58fc6b2 checked out; the one local gate run this round, because the merge is what it measures): exit 0. SKILL.md 815 lines, ceiling 819, headroom 4 — 815 is origin/main's own count after docs(pm-dispatch): enter the maintainer's 插队 and 契约面卡 tiers into the 取卡全序 (SKILL.md + core-rules twin) #19506/fix(pm): the claim HANDOVER protocol — one comment, four items, provenance instead of a liveness test; the reader accepts it and C9 keeps one red #19502, the PR net 0 on top; widest table row 342 / 342; core-rules.md 151 / 151; every other reference file at its ceiling with headroom 0. The dev's readings (815/819, 151/151, 342) are reproduced. RIGHT.

  6. CI on the head — read over REST from /commits/e58fc6b2…/check-runs (36 runs) at 2026-09-21T05:29Z, the pull_request workflows having started at 2026-09-21T05:27Z: TypeScript Type Check in_progress (rollup not yet reported; 1 of 4 legs success); Test Core in_progress (rollup not yet reported; 3 of 6 legs success); Dogfood Regression Gate success; Build Core skipped (paths filter); Temporal Conformance (live PG + MySQL) skipped (paths filter); Lint & Repo Gates in_progress; Governed Surface Queue Guard success. NOT MEASURED: TypeScript Type Check, Test Core, Lint & Repo Gates — named, non-blocking for this content verdict; the landing seat reads them green before the hand-merge. No conclusion other than success or skipped on any run.

  7. Merge-tree onto freshly fetched origin/main (8fc6a5f6): git merge-tree --write-tree origin/main e58fc6b2 exits 0, tree acceb03f — clean. In that tree SKILL.md is 815 lines against the landed ceiling 819 (['.claude/skills/pm-dispatch/SKILL.md', 819] in check-skill-line-ratchet.mjs on origin/main), core-rules.md 151, and the merged tree differs from origin/main in exactly the 19 files. (The dev's 99b7f9ee was the tree against ea64bbc6-era main; the tip has since moved, hence a different oid, same result.) RIGHT.

② Semver level

None: the round-5 delta is a merge of origin/main plus two composed lines under .claude/**, outside every released package's files[]; Clause-②: no and skip-changeset still hold (unchanged from 5755154226 ②). Carriers: none hung — the composition adds no rule that was not already on one side or the other.

③ Boundary flags

Implemented-by: claude/issue-19483-feature-axis-charter
Reviewed-by: session_012GcsUbuqFGBibkEDMRC1eE

VERDICT: PASS — Tier H (docs/NORTH-STAR.md + .claude/**); this record is not the landing record for Tier H: the maintainer merges by hand, after the NOT MEASURED contexts on e58fc6b2 read success.


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

Provenance — director seat, summon #25 (session_012GcsUbuqFGBibkEDMRC1eE), 2026-09-21T05:30Z


Generated by Claude Code

@hotlong
hotlong marked this pull request as ready for review September 21, 2026 07:16
@hotlong
hotlong added this pull request to the merge queue Sep 21, 2026
Merged via the queue into main with commit 61170fa Sep 21, 2026
40 checks passed
@hotlong
hotlong deleted the claude/issue-19483-feature-axis-charter branch September 21, 2026 07:41
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 28, 2026
…ate beside PATH and SIZE, plus the charter's external-contributions section (objectstack-ai#19526)

Fixes objectstack-ai#19470

Clause-②: no

## The ruling this lands

Maintainer, batch objectstack-ai#207 item 1, letter 是, verbatim and untranslated:
「fork PR 的处理同意你的意见。」 — recorded by the director on the card (comment
5754996112) as: **a fork PR is a proposal, not a delivery. No agent seat
flips it ready, enqueues it, arms auto-merge on it, or approves it —
ever.** It enters through the card door (card first; the human decides
the problem, not the code; the seat adopts the diff and never lands the
fork PR; a fork's CI is never approved to run by a seat, zero check runs
read NOT MEASURED, never green), with the minimal mechanism: a second
predicate beside the governed one in
`scripts/pm/check-governed-merges.mjs`, one sentence in AGENTS.md, one
short 〈外部贡献〉 section in the charter, the NOT-MEASURED wording. No new
label, no new sweep; the supply-chain clause is deferred until the first
such fork PR appears.

The live specimen, PR objectstack-ai#19342 (head `jinyitao123/objectstack`,
`author_association: FIRST_TIME_CONTRIBUTOR`, 0 check runs on `5fa7b6d`,
0 labels), is read here as evidence only. It stays untouched by this PR:
its disposal is the director's and triage's act in the same stroke, and
this branch writes nothing on it.

## What changed (five files, all on the claim's surface)

| file | before → after | net | what |
|:--|:--|--:|:--|
| `scripts/pm/check-governed-merges.mjs` | 6146 → 6226 lines | **+80**
(98 added, 18 replaced; budget ≤ +80, self-tests included) | the FORK
predicate beside PATH and SIZE; the check-run reading; a new self-test
battery beside the SIZE cases |
| `AGENTS.md` | 1109 → 1109 | **0** (ceiling 1109, headroom 0) | one
sentence in Prime Directive objectstack-ai#14's first paragraph, paid by one retired
restatement |
| `.claude/skills/pm-dispatch/SKILL.md` | 815 → 816 | **+1** (ceiling
819, headroom 3) | one rule line in 〈入队与落地〉 |
| `.claude/skills/pm-dispatch/references/core-rules.md` | 151 → 151 |
**0** | the landing-rule line rewritten in place to carry the twin |
| `.claude/skills/pm-dispatch/references/external-contributions.md` |
new, 16 lines | +16 (budget ≤ 20; widest line 120 B) | the ruled 〈外部贡献〉
section, four points + the deferred supply-chain line |

### 1. `check-governed-merges.mjs` — the FORK limb

- `forkVerdict(pull)` (pure, exported, beside `sizeVerdict`): reads
`head.repo.full_name` and `base.repo.full_name` off the PR object; NOT
MEASURED when there is no `base.repo` to compare against; a fork when
the head repo differs — **or is `null`** (the fork was deleted): a
deleted fork is still a fork, fail closed.
- `testVerdict(paths, { size, fork, checks })` carries `fork` and
`checks`; `humanMerge` fires on any of the three limbs;
`landsByHumanMerge` reads the fork limb too, so a fork exits on the
EXISTING GOVERNED code (3) through the Tier H terminal — every caller
that already routes 3 to the human hand routes a fork there without
learning a new code. `applyGeneratedExceptions` keeps the fork limb
across a generated-artifact lift (a lift moves a PATH, never the head
repo).
- `renderForkLines(fork, checks)` (pure, exported): the fork sentence
under the verdict — a PROPOSAL, never a delivery, whatever its paths; no
AI seat flips it ready, enqueues it, arms auto-merge on it or approves
it; a seat's review is required INPUT, never the permission; the owning
seat adopts the diff onto an internal branch (`Co-authored-by:` the
contributor) and lands THAT; requests to the contributor go only as
review comments on the fork PR, which is closed with thanks and the
landing link. When the PATH limb is clear the head line reads `paths:
none on the register — the HEAD REPO decides this PR:` (the SIZE limb's
shape); on a governed diff the sentence rides under the tier block, Tier
S included (a fork head on a `.claude/**` path is still adopted, never
landed).
- `--pr N` reads the head's check-run count off `GET
/repos/{slug}/commits/{sha}/check-runs` — one more GET, on the channel
already chosen for the PR read. `total_count: 0` prints `check runs on
head SHA: 0 — NOT MEASURED, never green` in the register the size limb
already uses; a count that did not read prints `NOT READ (reason) — read
as NOT MEASURED, never green`; a non-zero count prints nothing.
- `--test` and `--branch` cannot see a head repo and now say so on
stdout (`head repo: NOT MEASURED — this verdict cannot tell a fork PR
from an internal one; --pr N reads it`), the same discipline as the size
limb: a verdict silent about a leg it did not run reports a clearance it
never measured. The `--branch` / `--test` byte-identity pin still holds
(both print the same line).
- `--json` carries `fork` and `checks` beside `size`.
- Self-test: battery `⭐ the FORK predicate: head repo ≠ base repo is a
proposal, never a delivery` (6 cases, floor 6, roster 30 → 31), placed
between the SIZE battery and the audit-half battery, never at the tail:
fork head on ordinary paths ⇒ H route with the fork sentence and no
`ordinary queue landing applies`; `head.repo === null` ⇒ the same;
same-repo head on ordinary paths ⇒ unchanged (NOT governed, no fork
line); same-repo head on `AGENTS.md` / `.claude/agents/os-dev.md` ⇒ Tier
H / Tier S word for word, while a fork head on the Tier S path still
prints the fork sentence; no PR object ⇒ NOT MEASURED said; zero check
runs ⇒ the NOT-MEASURED line, 43 ⇒ absent, unread ⇒ `NOT READ`; and
`fetchPullFiles` against an injected fetch reads the head repo off its
own GET and the count off the head sha. Header docblock gains a "The
FORK predicate" section; the summary line names the battery.

### 2. `AGENTS.md` — one sentence, net 0

Prime Directive objectstack-ai#14, first paragraph, :264 before (102 B):

```text
    paragraph names fewer surfaces than the register — or more. When it reds, name the surface here.
```

:264–:266 after (113 B / 116 B / 106 B):

```text
    paragraph names fewer surfaces than the register — or more. When it reds, name the surface here. A fork PR
    (head repo ≠ base repo) is a proposal, never a delivery, whatever its paths: no AI seat readies, queues, arms
    auto-merge on or approves it; the owning seat adopts the diff onto an internal branch and lands that.
```

"whatever its paths" is the sentence's shape saying the fork rule is a
predicate on the PR, not a surface: the paragraph still names exactly
the register's six surfaces and no `**`-shaped span was added, so `pnpm
check:pm-governed-prose` stays green (quoted below).

**Payment (+2 lines bought by one retired restatement, ⛔ not by the
ceiling, not by re-wrap):** the three paragraphs of Prime Directive objectstack-ai#14
are greedy-packed already (878 / 1789 / 918 characters joined ⇒ 8 / 16 /
8 lines at the 120-column cap, exactly what they occupy), so re-wrap
buys nothing. Retired: the Skills section's line (pre-edit :800, 117 B,
plus its trailing blank line):

```text
⛔ **Both roots are governed surfaces** — `skills/` is Tier H, `.claude/skills/` Tier S (**Prime Directive objectstack-ai#14**).
```

It restated the register and its tiers, whose home is the directive it
pointed at. Surviving home and grep proof on this head: `grep -n
'skills/\*\*' AGENTS.md` → :6 (the CLAUDE-conflict clause), :260 (the
register names `.claude/**` and `skills/**`), :273 (Tier H names
`skills/**`); `grep -n 'Tier S' AGENTS.md` → :258, :276 (Tier S = all of
`.claude/**`), :292; `grep -n 'Both roots' AGENTS.md` → no hits. The
Skills section keeps its two-root catalog lines; only the restatement
left.

### 3. `SKILL.md` — one rule line in 〈入队与落地〉 (+1, 108 B)

Inserted at :643, directly under the section's pointer line (`- 细则见
references/landing-operations.md,落地窗口查阅。`):

```text
- fork PR = 提案,席位永不放行;采纳 diff 内部落地,见 `references/external-contributions.md`。
```

Placement (four axes): **业务需求** — the acts the rule forbids (ready / 入队
/ auto-merge / 批准) are the acts this section governs, so a seat reading
its landing checklist meets the fork rule where it would otherwise act;
**长远合理性** — one rule line, one pointer, the detail in a references file,
the same shape as the section's first line; **防 AI 犯错** — the line sits
before the 条款② gate and the PASS ⇒ ready ⇒ auto-merge line, so the fork
stop is read before the enqueue reflex; **创业阶段不扩散** — ≤ +1, no new
section. ⛔ Not in the 分诊 / 定级 region (:174–:175, :362, :368–:372, :379
are objectstack-ai#19494's) and not on PR objectstack-ai#19488's lines (the `area:*` rows,
:119–:134, :215, :243, :259, :294, :310, :371–:372, :470–:471). PR
objectstack-ai#19513 edits :632–:633 and :647 / :653 of the same section; :643 sits
between its two hunks with unchanged context on both sides, so the later
lander merges `origin/main` once with no conflict expected.

### 4. `references/core-rules.md` — the twin, paid in place (151 → 151)

:122 before (118 B) → after (112 B):

```text
- 验收后取路径面,命中规则层即分叉 ⛔ 不翻正式不入队;Tier S 席内达档复核 PASS 后入队。
- 验收后取路径面:规则层 ⛔ 不翻正式不入队,Tier S 达档 PASS 后入队;fork PR 永不放行。
```

Every landing-rule line in the core subset sat at 111–118 B of the 120 B
cap, so the twin could only ride a compression: 「命中…即分叉」 and 「席内…复核」 are
folded to 「规则层」 and 「达档」 (the SKILL.md lines they summarise are
unchanged), and the freed bytes carry the rule. No clause dropped. PR
objectstack-ai#19513 and PR objectstack-ai#19488 touch :55–:69, :102, :106–:113 of this file, not
:122.

### 5. `references/external-contributions.md` — new (16 lines, every
line ≤ 120 B)

Frame as its siblings (title, a 「见 SKILL.md 〈…〉」 pointer line, one rule
per line). Bytes per line: 45 · 0 · 117 · 117 · 0 · 113 · 77 · 97 · 92 ·
102 · 110 · 113 · 106 · 113 · 116 · 120. Content, the four points of the
ruling in substance: ① card first — triage's fire scans open PRs whose
head repo ≠ base repo, files a card from the PR body graded like any
card, posts the ONE fixed comment (`this repository works card-first;
filed as #N; this PR stays a draft until the card is graded`), a fork PR
with no card does not exist on the board; ② the human decides the
problem, not the code — a plain reproducible defect routes to a seat,
floor items (security / permission boundary, contract, feature) go to
the decision box as a business question; ③ the seat adopts the diff,
never lands the fork PR — internal branch, cherry-pick or
re-implementation, `Co-authored-by:` the contributor, full gate
derivation + at-tier review + the queue as for internal work, requests
to the contributor only as review comments on the fork PR, closed with
thanks and the landing link when the internal PR lands; ④ a fork's CI is
never approved to run by a seat, zero check runs read NOT MEASURED,
never green; the machine face (`check-governed-merges.mjs --pr N` routes
head repo ≠ base repo through the H(人合) exit, `head.repo` null the
same); and the deferred supply-chain line.

`check-skill-line-ratchet.mjs` does **not** require a CEILINGS row for a
new references file (it enumerates only `references/lanes/` for
uncovered files; the file is simply outside the ratchet's map, as
`references/instrument-discipline.md` on PR objectstack-ai#19513 is). No row was
added: the ratchet script is outside this card's file surface. Noted
under Acceptance notes for the seat.

## The two `--pr 19342` readings

Before (origin/main 8fc6a5f), `node scripts/pm/check-governed-merges.mjs
--pr 19342 :: exit 0`:

```text
governed-surface predicate: 0 of 4 path(s) hit the register (6 surfaces, repo-agnostic).
  ✅  NOT governed — ordinary queue landing applies to a PR with exactly this file list.
      Derived from GOVERNED_SURFACES, not recalled. Re-run on the FINAL file list: the register
      has grown several times in two days, and a reading taken earlier in the session is recall.
  size: 56 changed line(s) (+48 / -8) ≤ 5000 — under the human-merge threshold (generated files included in the count).
```

After (this head 0a50588), `node scripts/pm/check-governed-merges.mjs
--pr 19342 :: exit 3`:

```text
governed-surface predicate: 0 of 4 path(s) hit the register (6 surfaces, repo-agnostic).
  paths: none on the register — the HEAD REPO decides this PR:
  ⛔  FORK PR — head jinyitao123/objectstack ≠ base objectstack-ai/objectstack: a PROPOSAL, never a delivery, whatever its paths.
      The Tier H terminal, with its own reason: no AI seat flips it ready, enqueues it, arms auto-merge on it or approves it —
      ever; a seat's review is required INPUT, never the permission. The owning seat adopts the diff onto an internal branch
      (`Co-authored-by:` the contributor) and lands THAT through the ordinary gates; requests to the contributor go only as
      review comments here, and this PR closes with thanks and the landing link.
  ⚠️  check runs on head 5fa7b6d: 0 — NOT MEASURED, never green: a fork's CI does not run until a
      maintainer approves it, and a head that never ran looks exactly like one that passed. No seat approves it to run.
  size: 56 changed line(s) (+48 / -8) ≤ 5000 — under the human-merge threshold (generated files included in the count).
```

`--json` on the same run: `governed: false`, `tier: null`, `humanMerge:
true`, `fork: { measured: true, isFork: true, headRepo:
"jinyitao123/objectstack", baseRepo: "objectstack-ai/objectstack" }`,
`checks: { sha: "5fa7b6dc9d76657a57e30fbcd8010277261254f7", total: 0,
reason: null }`.

## Design choices, on the four axes

**`head.repo === null` reads as a fork (fail closed).** 实际业务需求: the API
returns `head.repo: null` exactly when a contributor deleted the fork
after opening the PR — a PR nobody can rebuild the head of is the least
reviewable shape a fork PR takes, and the population it comes from is
the fork population. 项目长远合理性: the predicate is closed (`head ≠ base`,
with an unreadable head on the far side of ≠), so no third state grows
beside it. 防 AI 犯错: the alternative — treating an unreadable head as
"not a fork" — is a `??` fallback in the consumer that turns a missing
fact into a clearance; the fail-closed reading is the loud one, and its
words name the deleted repo. 创业阶段不扩散: zero extra code — one `headRepo
=== null ||` in the predicate, one `(deleted fork repo)` in the words,
one self-test case. The one case deliberately left NOT MEASURED rather
than forked is a PR object with no `base.repo` at all (a fixture shape,
never seen from the API): there is nothing to compare against, and NOT
MEASURED is never a clearance either.

**Where the SKILL.md line sits** — the four axes are given under §3
above; the 分诊 / 定级 region belongs to objectstack-ai#19494 and the feature-axis lines
to PR objectstack-ai#19488, so the landing section was the only region on the claim.

## PM mechanism assumptions — verified

1. ✅ At 8fc6a5f `check-governed-merges.mjs` had 0 hits for `head.repo` /
`author_association` / `FIRST_TIME`; the PR object is fetched in
`fetchPullFiles` (`fetchJsonOver` on `GET /repos/{slug}/pulls/{n}`, the
read that gives `changed_files` and the size pair), and the proxy
returns `head.repo` (`jinyitao123/objectstack` on objectstack-ai#19342, `base.repo`
`objectstack-ai/objectstack`). The fork limb reads that same object; the
check-run count is a second GET on the same channel.
2. ✅ The H route's terminal reads `⚖️ landing tier: H(人合) — the
maintainer's hand, or an authorized APPROVED review (GOVERNED_APPROVERS)
and then the owning seat lands it`; the SIZE limb's terminal reads `The
same terminal as a Tier H governed diff: no seat flips it ready,
enqueues it, or arms auto-merge`. The fork sentence keeps the three
verbs, adds `approves it`, and adds the adoption step instead of the
seat-lands-it clause (a fork PR is never landed by the seat).
3. ✅ AGENTS.md 1109 / 1109; on the unchanged tree `pnpm
check:pm-skill-ratchet :: exit 0` and `pnpm check:pm-governed-prose ::
exit 0`; on this head both exit 0 again (quoted below).
4. ⏳ `node scripts/pm/check-governed-merges.mjs --pr` on this PR's own
number is run after the PR exists; the reading (expected: exit 3,
GOVERNED, Tier H — `AGENTS.md` and `skills`-free `.claude/**` on the
register, one Tier H path making the whole PR Tier H) goes into the
`os-dev-report` comment on the card. This PR stays draft for the
maintainer's hand.

## Verification (this head 0a50588)

- `node scripts/pm/check-governed-merges.mjs --self-test :: exit 0` —
441 assertions, the new battery registered at its floor; the two `--pr
19342` readings above; `--test README.md :: exit 0` (NOT governed, `head
repo: NOT MEASURED` on stdout), `--test AGENTS.md :: exit 3`; `npx
eslint scripts/pm/check-governed-merges.mjs :: exit 0`.
- The four charter gates, exits captured before any pipe: `pnpm
check:pm-skill-ratchet :: exit 0` (AGENTS.md 1109 / 1109 headroom 0;
SKILL.md 816 / 819; core-rules.md 151 / 151), `pnpm
check:pm-skill-id-lint :: exit 0`, `pnpm check:pm-governed-prose :: exit
0` (2 surfaces name all 6 registered surfaces and claim no others),
`pnpm check:nul-bytes :: exit 0`; control-character scan of the five
files: 0 hits.
- Derived union, `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` with no paths on 0a50588: 44 commands. Every
command run in the foreground with its exit captured before any pipe
(`cmd > log 2>&1; EXIT=$?`), then reconciled: `node
scripts/pm/dispatch-gates.mjs --ran ran-union.txt --repo
objectstack-ai/objectstack :: exit 0` — **44 derived, 44 run, 0
NOT-MEASURED, 0 UNRUN**, every exit 0. One family needed its inputs
built first: `pnpm --filter @objectstack/lint run
check:doc-formula-expressions` answered `PREREQUISITE NOT MET` (exit 3,
`@objectstack/formula` then `@objectstack/lint` not built in a fresh
worktree) until `pnpm --filter '@objectstack/lint...' build` ran under
the shared verification lock (`os-verify-lock.sh`, VERDICT command-exit
0, held 176 s); re-run on the built tree it exits 0 (22 record-scoped
examples judged clean). Heavy families in the union
(`check-governed-queue-guard.mjs --self-test`,
`check:pm-dispatch-gates`, `check-skills-token-ratchet.mjs`) all green.
- Local scope per the dispatch: no package's `pnpm test` / `typecheck`
is owed — the diff touches no `packages/**` source; `pnpm lint` (the
repo-level eslint) is CI's run, the edited script was linted directly.

## 维护者速读(草稿)

**改了什么** — 三处一致的规则:fork 上来的 PR(head 仓 ≠ base 仓,含 fork 已删的情况)是提案不是交付。①
`check-governed-merges.mjs` 在「路径受管」「改动超 5000 行」之外加了第三个判据「head 是
fork」,命中即走既有的「人合」出口,并打印自己的理由句;`--pr` 同时读 head 上的 check run 数,0 条时打印「NOT
MEASURED,不是绿」。② `AGENTS.md` 第 14 条基本原则加一句(行数不变,用 Skills 节里一句重复表述抵付)。③ PM
技能的落地条款加一行,核心条款一行原地改写承接,并新增一页 `external-contributions.md`
写清四步:先立卡、人裁问题、席位采纳 diff 内部落地、fork 的 CI 席位不代批。供应链条款按裁决延后。

**为什么改** — 您 2026-09-21 裁了「fork PR
的处理同意你的意见」。之前合并前防线只看改了哪些文件、只约束我们自己的席位,objectstack-ai#19342 那样的外部 PR(OAuth 放宽到明文 HTTP,0
条 CI)按机器判定可走普通队列;现在它被机器点名为提案,任何席位都不能放行。

**风险与代价(含回滚)** — 代价:每张外部 PR 都要您(或授权批准账户)拍板,今天 100 张里 1 张;`--pr` 多一次 API
读。行为变化:`--test` / `--branch` 的输出多一行「head 仓未测」提示,不改退出码。回滚:revert 本 PR 一个
commit 即可,无数据、无迁移。

**席位意见** — (留空,席位定稿时填)

**你要做的** — 点合并(Tier H:本 PR 改了 `AGENTS.md`,只由您的手落地)。objectstack-ai#19342 本身按同一批裁决由总监席 /
分诊席处置,不在本 PR 内。

## Acceptance notes

- `references/external-contributions.md` carries no CEILINGS row in
`check-skill-line-ratchet.mjs` (the ratchet does not require one and the
script is outside this card's surface), so the new file is invisible to
the line ratchet until pinned; a first pin at the landed count (16) is
not a raise. carrier: the `domain:skills` seat.
- `--pr N` now spends one extra GET per run
(`/commits/{sha}/check-runs?per_page=1`) on the chosen channel; a failed
read is carried as `NOT READ (reason)` and never a zero.
- `--test` / `--branch` stdout gained the `head repo: NOT MEASURED` line
under every verdict — deliberate, mirrors the size limb; a grep reader
keyed on `NOT MEASURED` alone now matches on every `--test` run without
size flags too (it already did for the size line).
- The seat's decision analysis left three confidence gaps open
(`pull_request_target` in four workflow files, the MCP merge route
against a fork head, fork PR history beyond the newest 100); none is on
this card's surface and none was measured here. carrier: the
`domain:skills` seat.
- PR objectstack-ai#19342 is not addressed here; it remains open for the director's /
triage's disposal.

---
_Generated by [Claude
Code](https://claude.ai/code/session_017ETYWqMQD4qMtZzAGovWNi)_

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 28, 2026
… questions only; C5 and the patrol anchor stop blocking; at-tier review scoped to what ships and read from CI (objectstack-ai#19496) (objectstack-ai#19513)

Fixes objectstack-ai#19496

Clause-②: no

**Tier H — the maintainer merges this by hand.** The diff touches
`AGENTS.md` and `.claude/**`, so one Tier H path makes the whole PR Tier
H: no seat flips it ready, queues it, or arms auto-merge, and no agent
account approves it.

Authorization, verbatim and untranslated — maintainer, 2026-09-21
(ruling objectstack-ai#208 on objectstack-ai#19491):

> 「19491 接受你的建议,并立刻派发处理相关任务。」

## What lands — five charter edits, text only

Nothing under `scripts/`, `.github/` or `packages/` is touched. The C5
code demotion, the patrol schedule and the CI self-test scoping are
their own cards.

**R1 — a non-zero `--pair` blocks landing only on rows that answer a
definite question.** `SKILL.md` 〈入队与落地〉 and
`references/contract-review.md` 落地前检三条:

```text
- `Clause-②: yes` 认领同笔卡上挂标;开 PR 跑 `--pair N`:只确定性行红才挡请审,C5 只印读数。
- 0 = 确定性行全清;4 = 任一不成立,只确定性行红才挡落地;3 = 环境答不了 ⛔ 不作干净。
- 确定性行 = 记录在案、`Served-tier:`、双载体一致、认领形;C5 放宽 tell 只报告,归复核裁。
```

`AGENTS.md` Prime Directive objectstack-ai#14 is where the conjunct lives — `git grep
-n -- '--pair' AGENTS.md .claude` is the census (1 hit in `AGENTS.md`, 5
in `.claude`). Tier S now reads `reads 0 on its definite rows (⛔ never
C5) and every check is green`; the paragraph was re-wrapped from that
sentence onward and `AGENTS.md` stays at 1109 lines.

**R2 — the rule line**, next to the tooling rules ruling objectstack-ai#202 B landed,
in 〈分诊座位职责〉's filing classes:

```text
- 只报告的仪器,报错不配 dev:猜意图的只印读数,误报席位一句推翻,⛔ 不立卡不派 dev。
```

**R3 (charter half) — the patrol anchor stops being a precondition.**
The two 〈执行座位职责〉 lines are deleted; one line replaces them, mirrored in
`references/core-rules.md`:

```text
SKILL.md      - 半状态巡查按需跑(分诊席每日对账可调),H 行是读数不是前提;⛔ 不因锚行停派发。
core-rules.md - 半状态巡查按需跑,其 H 行是读数不是前提,⛔ 不因锚行停派发。
```

**R5 — at-tier review: scope and shape**, in
`references/contract-review.md` 〈复核归属与资格〉:

```text
- 复核面 = 出货给用户或 agent 的:`content/docs/**`、`apps/docs/**`、CHANGELOG/`.changeset` 散文。
- 同含已发布 schema 与 governed 规则文本;三面皆不碰 ⇒ CI 加席位自读,⛔ 不起第二个 agent。
- 复核形状:只读 diff 与卡片,check 结论取 head 的 check-runs,⛔ 永不本地重跑派生门禁族。
```

`Served-tier:` and the record shape are unchanged.
`check-clause2-carriers --template` prints nothing that contradicts the
shape: its ③ is the record's boundary-flag heading and it prescribes no
local gate run, so no script edit was needed (checked; reported below as
a reading, not a finding).

**R6 — 〈仪器纪律〉** is a new reference,
`references/instrument-discipline.md` (11 lines), with exactly one
pointer line in SKILL.md 〈平台读数纪律〉, placed one line below the
advisory-red rule:

```text
- 仪器纪律(硬门禁面、只报告面、新增授权、工具位)见 `references/instrument-discipline.md`。
```

The section itself:

```text
- 硬门禁只答有确定答案的问题:受管登记表、队列守卫、CI 测试、复核记录在不在。
- 判意图的仪器(放宽 tell、半状态巡查)只印读数 ⛔ 不挡落地,误报由席位一句话推翻。
- 放宽 tell(C5)由 `scripts/pm/check-widening-tells.mjs` 印 file:line,归达档复核裁。
- 只报告的仪器不配 dev:⛔ 不立卡、不派 dev、不开 PR;它的在途工作只有删除。
- 新增门禁、巡查行或棘轮须在卡上引维护者原话,⛔ 无原话不新增;首行四件恒硬。
- 工具位只有一个,先花在删除上;`dispatch-gates.mjs` 冻结,只在它喂的 workflow 坏了时碰。
- 出处:维护者 2026-09-21 逐字「19491 接受你的建议,并立刻派发处理相关任务。」
```

**Why a new file rather than `landing-operations.md`.** Every file an
at-tier reader already opens for landing or gates stands at its ceiling
with zero headroom — `landing-operations.md` 69/69, `true-green.md`
32/32, `review-checklist.md` 77/77 — and the section costs 11 lines, so
hosting it in one of them means deleting live rules, which this card
forbids. The pointer instead sits where the reader deciding what a gate
reading means already is: 〈平台读数纪律〉, right after the two lines on a gate
job's conclusion and an advisory red. The new file carries no `CEILINGS`
row, because that row is an edit under `scripts/**` (out of scope here)
and R6's own rule says a new ratchet needs the maintainer's sentence on
its own card — reported below.

## The line ratchet — no ceiling raised, every added line paid in place

`pnpm check:pm-skill-ratchet` exit 0. Per-file counts on head
`fec2177089`, after merging `origin/main`:

| file | lines | ceiling | headroom | net this PR |
|:--|--:|--:|--:|--:|
| `.claude/skills/pm-dispatch/SKILL.md` | 819 | 819 | 0 | 0 |
| `.claude/skills/pm-dispatch/references/contract-review.md` | 60 | 60 |
0 | 0 |
| `.claude/skills/pm-dispatch/references/core-rules.md` | 151 | 151 | 0
| 0 |
| `AGENTS.md` | 1109 | 1109 | 0 | 0 |
| `.claude/skills/pm-dispatch/references/instrument-discipline.md` | 11
| none | — | new file |

What paid for the added lines — de-duplication only, no rule deleted,
each surviving carrier named:

- SKILL.md 〈复核〉's two 受管面两层 lines became one. The Tier H enumeration it
dropped is the 〈复核〉 line three above it (governed 面统一定义), and 四件套 is
stated at 路径面命中规则层 ⇒ ACCEPT 换终局四件套.
- contract-review.md's 双载体同笔挂 line is stated in SKILL.md 〈入队与落地〉
(`needs:contract-review`(恒英文)由席位同笔挂:PR 一现即挂 PR;报告先到则先挂卡); its unique
tail, ACCEPT 补齐 PR 侧, rides the next line.
- contract-review.md's two `Implemented-by:` / `Reviewed-by:` spelling
lines became one pointer at `--template`, which prints both fields
verbatim — and the record-shape line three above already cites that
template.
- contract-review.md's standalone Tier H/S landing line left; the tier
outcome now rides the 落地前检三条 line itself, so
`references/lanes/director.md`'s pointer at this block still resolves,
and SKILL.md 〈复核〉 carries the full two-tier rule.
- `AGENTS.md`: 43 added bytes absorbed into the paragraph's own slack by
re-wrapping from the edited sentence onward; no line was bought.

## Collision — both charter PRs merge clean

- **PR objectstack-ai#19462** (`claude/issue-19457-charter-product-only-queue`, head
`36ab00aa`) **merged into `main` during this round.** `git merge-tree
--write-tree 36ab00a HEAD` was exit 0 with zero conflict markers before
that, and this branch then merged `origin/main` (`48c39e00`) with no
conflict. Its `tooling` label rules, its two gate-false-positive lines
and its ratchet bump (SKILL.md 813 → 819) are all present on this head.
- **PR objectstack-ai#19488** (`claude/issue-19483-feature-axis-charter`): the card
named head `420bd091`; the branch tip is now `16418377`. `git merge-tree
--write-tree 1641837 fec2177` → **exit 0**, tree
`02a7323a2d779974bd035082ad954eaf4cd15a21`, zero conflict markers. Every
line that PR touches is untouched here.

## Acceptance

| grep | result |
|:--|:--|
| `git grep -n '0 才请审' .claude` | 0 hits (exit 1) |
| control `git grep -n -- '--pair' .claude` | 5 hits (os-dev.md 1,
SKILL.md 1, contract-review.md 2, platform-readings.md 1) |
| `git grep -n '锚行未处置' .claude` | 0 hits (exit 1) |
| control `git grep -n '半状态' .claude` | 24 hits across 8 files |
| `git grep -n 'C5' …/references/contract-review.md` | 1 hit, naming it
只报告 |

## Gates

Derived on this diff with `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack` — 23 commands; the derivation also
names 11 wide-population, 53 artifact-roster, 14 pending-changeset and 2
CI-valued families as outside that list, so this is not a complete
account of CI. Every exit code was captured **before** any pipe (`cmd >
log 2>&1; e=$?`). Reconciled with `--ran`: **23 derived, 23 run, 0
NOT-MEASURED, 0 UNRUN.**

```text
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-governed-queue-guard.mjs --self-test :: 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:docs-audit-scope :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:pm-expected-skips :: exit 0
pnpm check:pm-governed-merges :: exit 0
pnpm check:pm-governed-prose :: exit 0
pnpm check:pm-half-states :: 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:required-contexts :: exit 0
pnpm check:skill-frame-sync :: exit 0
pnpm check:watch-hint-literal :: exit 0
```

Three more, run because this card names them:

```text
pnpm check:pm-widening-tells :: exit 0      (self-test only — 525 cases; checker health, not a verdict on this diff)
node scripts/pm/check-widening-tells.mjs --declaration no --diff pr.diff :: exit 0   (a real verdict: no tell)
pnpm check:pm-label-desc-cap :: exit 0
pnpm check:pm-settings-deny-roster :: exit 0   (its roster lives under .claude, which this diff is in)
```

Two gates first answered `exit 3` (PREREQUISITE NOT MET) in a fresh
worktree and were re-run after `pnpm install`, and
`check:doc-formula-expressions` after `pnpm exec turbo run build
--filter=@objectstack/formula --filter=@objectstack/lint` under the
shared verify lock (VERDICT command-exit 0). Those 3s are recorded as
what they are — nothing measured, not a finding.

`skip-changeset` applies: the diff is `.claude/**` plus `AGENTS.md`,
nothing under `packages/**`, and no published `files[]` content moves.

## Acceptance notes — out of scope, not filed by the dev

- SKILL.md 〈状态模型〉 still says 派发与折叠检查时读半状态巡查锚的 H17 触发文件索引. With the
patrol's schedule retired on its own card, that index can go stale; this
card's R3 scope was the two 〈执行座位职责〉 lines only. Dedupe words: 半状态巡查锚,
H17, 触发文件索引, 折叠检查.
- `references/instrument-discipline.md` carries no `CEILINGS` row, so it
is the one un-ratcheted file on the pm-dispatch surface. Adding the row
is an edit under `scripts/**`, and by R6's own rule a new ratchet needs
the maintainer's sentence on its card. Dedupe words: CEILINGS,
instrument-discipline, ratchet row, un-ratcheted reference.
- `check-clause2-carriers --template` prints no line contradicting R5's
shape (checked; no script edit).

## 维护者速读(草稿)

**改了什么** — 把「仪器」这件事写成纪律:`--pair`
这类硬门禁只在能给出确定答案的行上挡落地(复核记录在不在、档位行在不在、两个标签载体一不一致、认领形对不对);猜意图的那一行(C5 放宽
tell)从此只印读数,由达档复核的人判。半状态巡查从「每轮派发的前置条件」降为「按需跑的读数」。达档复核的范围收到「会出货给用户或 agent
的东西」,形状收到「读 diff 加读 CI 的 check-runs」,不再本地重跑门禁。新增一页〈仪器纪律〉,把这几条连同「只报告的仪器不配
dev」「新增门禁要维护者一句话」「工具位先花在删除上」写在一起。

**为什么改** — 裁决 objectstack-ai#208 的实测:工具链自己占了三到四成的合并量、每个 PR 三分之二的 CI 关键路径;把 objectstack-ai#19314
挡住的那道门,本体只是两句章程话,不是 CI 门禁。一次达档复核 24 万 token、29 分钟,其中最大一块是在本地重跑 CI 已经跑过的
37 个门禁族。这三件都不是删代码能解决的,是纪律写错了地方。

**风险与代价(含回滚)** — 代价是硬门变软:C5 不再挡人,漏网要靠复核的人看见。回滚是一次
revert,因为全是文本。棘轮一行没抬,新增的行全部用去重付账,幸存载体逐条点名在上面;唯一的新面是那一页新文件,它暂时没有棘轮行。

**席位意见** —

**你要做的** — 读这五处改动,同意就人工合并(Tier H,队列与 auto-merge 都不适用)。

## Round 2 (seat's note)

Head `96774e44ef`. The at-tier review (5755678024, FAIL) named three
items; all fixed in one push: R5's obligation now keys on the **face**,
not the lane (`references/contract-review.md` 〈复核归属与资格(按面)〉 lines 24–27,
SKILL.md line 647, plus the two lane-keyed twins at SKILL.md 533 and
core-rules.md 113 — 「三面」 is now 「五面」 and the published schema names its
path `packages/spec/src/**` non-test); `origin/main` (`ea64bbc6e8`)
merged with the SKILL.md 180/181 conflict resolved keep-both;
`instrument-discipline.md` cites ruling 208 / card 19491 / comment
5755284987 with bare ids (the `#` spelling is what
`check:pm-skill-id-lint` refuses). Ratchet: SKILL.md 815/819,
contract-review.md 60/60, core-rules.md 151/151, AGENTS.md 1109/1109.

CI: this head has zero GitHub-Actions runs — a `.claude/**` plus
`AGENTS.md` diff matches no PR-level workflow paths; the merge queue's
`merge_group` run supplies the required contexts, so the empty check
list is the known shape and not a stall.

---
_Generated by [Claude
Code](https://claude.ai/code/session_012GcsUbuqFGBibkEDMRC1eE)_


---
_Generated by [Claude Code](https://claude.ai/code)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
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/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

4 participants