Skip to content

decision: which model serves the clause-② contract review — fable on every lane (ruling 5771798588), or fable only for the spec / skills lanes and governed surfaces with opus elsewhere? #23352

Closed

Description

@objectstack-fleet

Ruled: 6159870311 · letter B′ · 2026-10-14T03:02Z

Filing gate ② a decision only the maintainer can make.

维护者速读

条款② 契约复审现在一律用 Fable(CONTRACT_REVIEW_TIER = 'claude-fable-5-1'),依据是你 9 月 22 日的「复核档应该就是 fable 啊」。问题是:objectui domain:ui 这类非 spec 车道的复审,用 Opus 够不够。

今天这条车道的三次 Fable 复审都没找到代码问题,各找到一处席位审查的漏洞:

三处都是清单核对或翻先例就能发现的,不需要深推理。每次花 16–37 万 token、约 10 分钟。复审一提修改,PR 就要换新 head,新 head 还得再审一次,成本跟着翻倍。

选项:

  • A:维持现状,所有复审用 Fable。
  • B:按车道分。spec / skills 车道的条款② 复审和受管面复审保持 Fable;其他车道(ui、devx、services 等)的复审用 Opus。
  • C:按复审类型分。首次复审用 Fable;head 只在版本声明、文档或纯文字上移动的再审用 Opus。
  • D:所有复审改用 Opus。

推荐 B,并以本任务里的 Opus 再审作对照:如果 Opus 漏掉 Fable 会抓到的东西,回到 A。回一个字母:A / B / C / D。

四棱(os-decision-facets)

  • ① 项目长远合理性: 复审要守的是契约。spec / skills 车道改的是 schema 和规则本身,错了全车队受影响,值得最强的审查。其他车道的条款② 多是一个翻译键、一处行为放宽,判据是清单和先例。B 把强度放在风险所在处。C 省的是机械再审。D 在高风险车道也降了档。
  • ② 实际业务拉动: 有实测。本车道今天三次复审的发现、耗时和 token 如上,记录分别是 6151614668、6151661549、6158000763。三个 PR 当前都在等新 head 的再审。
  • ③ 防 AI 犯错: 复审防的是席位和 dev 的盲区:没核实的推测、漏写的声明、判错的级别。这三类在 Opus 下大概率仍能被抓到,但目前没有对照数据。B 的置信缺口靠本任务的 Opus 再审来补。A 最稳。D 风险最大:spec 车道的契约错误一旦漏过,会发布出去。
  • ④ 创业阶段不扩散: B / C 不新增门禁,只把一个常量拆成按车道或按类型取值,多一条规则行。A 零改动。D 改一个值。

Prior rulings read: contract review tier, CONTRACT_REVIEW_TIER, 复核档 → 4: the maintainer's 「复核档应该就是 fable 啊」 / 「某个agent临时没有fable给的特殊授权,不应该改变skills」 (record 5771798588 on #7623, 2026-09-22); #17285 (the seat-tier policy, landed as PR #17294); #21187 (prose off the review surface); and today's interim waiver 6158097279. ADR: none. Thread: none.

一句话问题

条款② 契约复审的模型档:所有车道都用 Fable,还是只在 spec / skills 车道和受管面用 Fable,其他车道用 Opus?

Governing text

  • scripts/pm/dispatch-gates.mjs:export const CONTRACT_REVIEW_TIER = 'claude-fable-5-1';。它的 docblock 写明:"a tier word is RETIRED only by the maintainer's explicit ruling that NAMES a retirement",并且 "this constant is a property of the lane's governance"。
  • .claude/skills/pm-dispatch/references/contract-review.md:「欠不欠按面判 ⛔ 不按车道」;记录首行 Served-tier: 写常量名 CONTRACT_REVIEW_TIER。
  • 维护者 2026-09-22:「复核档应该就是 fable 啊」。

前提(每条带 re-check 命令)

  1. 现值。 Re-check(objectstack):grep -n "export const CONTRACT_REVIEW_TIER" scripts/pm/dispatch-gates.mjs。
  2. 本车道今天的三次复审:
  3. 再审成本。 一次修补推新 head,就要重跑 CI(全量约 25 分钟),再做一次复审。现行规则只对「纯重生成」的 head 移动豁免(contract-review.md 落地前检两条下的例外)。
  4. 本任务的 Opus 再审(6158097279 授权)会在三个 PR 的新 head 上留下记录。执行席把它们的发现附在本卡评论里作对照。

选项 × 真实代价 × 工作量

选项 做什么 后果 工作量
A 不改 每次复审都是最强档;本车道复审成本维持 无
B 常量拆成按车道取值:spec / skills 车道的条款② 和受管面用 claude-fable-5-1,其他车道用 Opus;Served-tier: 记录随之写所用档的常量名 非核心车道复审更快更省;高风险车道不变 objectstack domain:skills 1 个 PR(Tier H)
C 首审 Fable;head 只在 .changeset/**、文档或纯文字上移动的再审用 Opus 省掉机械再审的成本;首审强度不变 同上,外加一条「仅文字移动」的判据
D 常量改为 Opus 所有复审最省;spec 契约错误漏过的风险上升 改一个值

推荐 + 回退 + 置信缺口

  • 推荐 B,回退 A。
  • 置信缺口: 没有同输入的 Opus 对 Fable 对照。补法是本任务三次 Opus 再审的发现:如果 Opus 漏掉 Fable 在同类输入上会抓到的东西,就回到 A。

裁后执行

  • A: 本卡以 not_planned 关闭,引用裁决。临时授权 6158097279 随本任务结束失效。
  • B / C / D: objectstack domain:skills 开执行卡:改常量(或拆成按车道、按类型的映射),改 contract-review.md 的 Served-tier: 判据与 record-recognisers.mjs 的模板,self-test 钉住新映射。

Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    席位意见 · director seat (summon #37, session_01LqNgdPZB2Jnr5HpGbaqLeB), read on the maintainer's 「然后 23352 决裁」, 2026-10-14T02:28Z

    Read before writing (tier words only; no model name enters a GitHub artefact): the card; scripts/pm/dispatch-gates.mjs CONTRACT_REVIEW_TIER and its docblock ("a tier word is RETIRED only by the maintainer's explicit ruling that NAMES a retirement"; TIER_DEFAULT lives in dispatch-gates.data.mjs); record-recognisers.mjs:432 (servedTierStands accepts exactly CONTRACT_REVIEW_TIER_NAME) and its caller check-governed-queue-guard.mjs:840 (below-tier); references/contract-review.md on main dc393266f (line 7 「欠不欠按面判 ⛔ 不按车道」, line 16 Served-tier: must name CONTRACT_REVIEW_TIER, line 30 the pure-regeneration exception). The record: #17285 → PR #17294 (2026-09-10, +120/−52: the maintainer's rulings 1–6, verbatim 「按照你的新建议,只有 spec 和 skills 车道需要fable 对吧。」→ 对; the table: ui/engine/services/cli/devx/hotcrm seats' clause-② review = the lane seat's own default-tier review plus the gates, the contract-review tier "never"); #19496 → PR #19513 (2026-09-21, ruling #208 on #19491 「19491 接受你的建议,并立刻派发处理相关任务。」: R5 scopes the at-tier review to what ships, which the charter rendered as 「按面判 ⛔ 不按车道」); 5771798588 (2026-09-22: the tier's identity, 「复核档应该就是 fable 啊」, a temporary lack of authorization never changes the governed text); #21192 (2026-10-01: three contract faces; prose to the ACCEPT); the interim waiver 6158097279 (2026-10-14).

    推荐:B′(按面定档),带 C 的再审豁免;回退 A;⛔ D。

    四维分析(业务立场)

    • ① 项目长远合理性: 两条裁决各管一个轴。9 月 10 日裁的是用哪档:契约复审档只给 spec 席的条款② 复审与 skills 席;9 月 21 日裁的是欠不欠:按出货面判,不按车道。今天的文本把两轴合成了「碰面即欠达档复审」,于是 ui 车道一个翻译键的条款② 也上了契约复审档,这不是任何一条裁决说过的话。B′ 把两轴接回去:欠不欠按面判(9 月 21 日),档位按触发复审的面定(9 月 10 日):已发布 schema(packages/spec/src/**)与受管规则文本触发的复审在契约复审档(这两面本来就是 spec 席与 skills 席的面);只凭 Clause-②: yes 申报触发的复审(应用与 UI 代码里的放宽、翻译键、版本声明)在默认判断档,记录的 Served-tier: 写 TIER_DEFAULT 的常量名,识别器按面接受。主流做法同向:按路径分级的审查(受保护目录的必审人、CODEOWNERS 的强制复核)把最强的审查放在契约所在处,不放在每个车道。
    • ② 实际业务拉动: 实测:ui 车道三次契约复审档复审各 16–37 万 token、约 10 分钟,三次都没找到代码正确性问题,找到的三处(未核实的推测、漏写的版本声明、定级 patch 应为 minor)都是派发席 ACCEPT 清单本就该核的项(pm-dispatch: owe the isolated contract review on three contract faces; changeset and docs prose move to the seat's ACCEPT #21192 之后 .changeset 与文档散文归 ACCEPT 逐句对照)。一次修补推新 head 就要再审一次,成本翻倍。你的常设判据「多花钱的我不要」「让车队提速」直接命中。
    • ③ 防 AI 犯错: 复审防的是席位与 dev 的盲区。B′ 在契约所在的两面保持最强档;默认判断档的复审对清单类发现足够,置信缺口由本任务三次默认档再审(6158097279)作对照:若默认档漏掉契约复审档在同类输入上会抓到的东西,那条车道回到 A。记录首行永远写明服务档的常量名,没有静默降档;D 在 spec 面也降档,契约错误一旦漏过会随发布出去,且与 9 月 22 日「复核档就是契约复审档」的裁决相抵。
    • ④ 创业阶段不扩散: B′ 不新增门禁:一个常量变成按面取值的两行映射(面的枚举已经存在:复核面三面与受管表),识别器多接受一个常量名;C 的豁免是现有「纯重生成例外」的同形扩展(head 只在复核面之外的散文面移动 ⇒ 原记录继续管,判据机读已提交树);A 零改动但持续付费;D 改一个值但推翻一条裁决。

    与两条裁决的关系(记下,免得下次再漂)

    工作量(按卡面列): B′:objectstack domain:skills 1 个 PR(Tier H 受管面):contract-review.md 归属两行、record-recognisers.mjs 按面接受 TIER_DEFAULT 的常量名与模板、dispatch-gates.mjs 导出该常量名、队列守卫读它、self-test 钉住映射 · 先例 PR #17294(+120/−52,5 文件)与 PR #19513;C 的豁免加一条机读判据 · 先例 eff0a96(纯重生成例外,#19634)。A:零。D:改一个值。

    置信缺口:没有同输入的两档对照,三次默认档再审是唯一的对照数据,尚未贴到本卡;objectui 侧没有 dispatch-gates.mjs,它按规则文本执行,映射要在两仓的规则文本里都能读到。自检:只看①选 B′;②③④ 是否翻转:否(同向)。

    裁后执行: 裁 B′:domain:skills 席位认领执行卡(本卡即执行卡,裁后转 pm:queue),一个 Tier H PR 交你合并;ui 席位把三次默认档再审的发现贴到本卡作对照;本卡在 PR 合并后关闭。裁 A:本卡 not_planned 关闭,豁免随本任务结束失效。

  2. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #2 item 1 · letter B′ · maintainer 「同意」 2026-10-14T02:57Z

    Director seat, summon #37, session_01LqNgdPZB2Jnr5HpGbaqLeB, on the seat's reading 6159538514 (B′ with C's re-review exemption; fallback A; ⛔ D), presented in chat with the reasonableness assessment the maintainer asked for (「你可以帮我综合评估合理性,和我讨论」); the maintainer's 「同意」 is on B′ with C.

    What the ruling binds (letter B′ with C):

    1. Whether an isolated contract review is owed stays by surface (charter: instrument discipline — hard gates answer definite questions only; C5 and the patrol anchor stop blocking; at-tier review is scoped to what ships and reads CI instead of re-running gates (ruling #208 on #19491) #19496 R5; pm-dispatch: owe the isolated contract review on three contract faces; changeset and docs prose move to the seat's ACCEPT #21192's three contract faces), never by lane.
    2. The tier of that review follows the face that made it owed: a published schema (packages/spec/src/** non-test exports) or governed rules text → CONTRACT_REVIEW_TIER; a review owed only by a Clause-②: yes declaration (a widening in application or UI code, a translation key, a version declaration) → TIER_DEFAULT, run as the lane seat's review of record, its Served-tier: line naming TIER_DEFAULT's constant name. servedTierStands and the queue guard accept the constant the face maps to, exact, never a floor.
    3. Re-review exemption (C): a head that moves only on faces outside the review surface (the prose faces pm-dispatch: owe the isolated contract review on three contract faces; changeset and docs prose move to the seat's ACCEPT #21192 moved to the ACCEPT: .changeset/**, CHANGELOG, content/docs/**, apps/docs/**) keeps the existing record, decided on the committed trees like the pure-regeneration exception (fix(pm): a pure-regeneration head move keeps the contract-review record, decided on the committed trees #19634); the PR carries the provenance line.
    4. Nothing retires: CONTRACT_REVIEW_TIER's identity (5771798588) and the by-surface rule (charter: instrument discipline — hard gates answer definite questions only; C5 and the patrol anchor stop blocking; at-tier review is scoped to what ships and reads CI instead of re-running gates (ruling #208 on #19491) #19496) stand; Model-tier policy: the contract-review tier is reserved for the skills seat (three protocol files + the published skills/** catalogs), the spec seat's clause-② review, and the maintainer-summoned director; triage and every other seat run the default tier #17285's tier table is restored on the tier axis. The interim waiver 6158097279 lapses when this lands.
    5. Control: the three default-tier re-reviews on objectui PRs feat(spec): retire the authorable AdvancedPluginLifecycleConfig surface, keep the host-driven lifecycle library (#11825, ADR-0049 route 2) #12336, [finding] The first worktree at a new set of package inputs pays a ~431s cold closure build UNDER the shared verify lock; every sibling afterwards pays 0.2s #12337 and [finding] HotReloadConfig.stateStrategy 'disk'/'distributed' are silent memory fallbacks, and distributedConfig has zero readers — declared≠enforced inside the KEPT host-driven library #12340 are posted on this card by the ui seat as the comparison; if the default tier misses what the contract tier catches on like input, that face returns to A by a one-line ruling.

    Workload of the letter (the card's column): objectstack domain:skills · one Tier H PR (contract-review.md's two ownership lines; record-recognisers.mjs accepts TIER_DEFAULT's name by face and prints it in --template; dispatch-gates.mjs exports that name; check-governed-queue-guard.mjs reads it; self-tests pin the mapping and the exemption) · precedents PR #17294 (+120/−52, 5 files), PR #19513, eff0a9622 (#19634). objectui has no dispatch-gates.mjs: the rule text covers it.

    Execution: this card is the execution card: needs-user-decision removed and pm:queue added in this act for domain:skills; the PR stays a draft for the maintainer's merge; the card closes on landing. The body's first line carries Ruled:.

  3. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · the director seat dispatching on the maintainer's word 「23352 你负责派发。」 (this seat's session, 2026-10-14T03:03Z)
    Session: session_01LqNgdPZB2Jnr5HpGbaqLeB
    Account: os-zhuang
    Branch: claude/issue-23352-review-tier-by-face
    Worktree: objectstack-issue-23352
    Domain: domain:skills
    Seat: domain:skills#9 (the director seat dispatching into the lane on the maintainer's word)
    File surface (at origin/main dc393266f or later): .claude/skills/pm-dispatch/references/contract-review.md (ceiling 60, now 40 lines), scripts/pm/record-recognisers.mjs (servedTierStands, the Served-tier: reading and --template), scripts/pm/dispatch-gates.mjs (export the default tier's constant NAME beside CONTRACT_REVIEW_TIER_NAME; the constant's value site stays dispatch-gates.data.mjs), scripts/pm/check-governed-queue-guard.mjs (the below-tier reading by face), their self-tests; SKILL.md only if a line there restates the tier (ratchet: net-zero lines). ⛔ Not CONTRACT_REVIEW_TIER's value, ⛔ no model name in any file, ⛔ no issue number in a skill file, ⛔ not .github/workflows/**.
    Container & model: M, mode:subagent, model: default tier (dispatch-gates --tier on the paths: no path-derived mandate). Tier H by the governed table (.claude/**, scripts/pm/**): the PR stays a draft for the maintainer's merge; ⛔ no seat readies, queues or approves it.
    Clause-②: no (no published door; governed rules text and PM tooling)
    Responsibility: n/a — not a defect card
    Thread-read: 6159870311
    Ruling-ref: this card's ruling (batch #2 item 1, letter B′ with C, 6159870311); #17285 → PR #17294; #19496 → PR #19513; 5771798588; #21192; #19634 (eff0a9622)
    Serial constraints cleared (the six open PRs' titles and heads read in this act): #23209 (tooling(pm), the fleet relay's release refresh) is the only open PR under scripts/pm/**; its surface is fleet-write/** and release.yml, disjoint from this card's four files; #23370 (seat 2's ADR-0138 sentence from #23267's ruling C) is docs/adr/** only. Merge origin/main before opening the PR and again before the maintainer's merge if either lands first; ⛔ no rebase.
    Resume-from: none

    This act moved the card needs-user-decision → pm:dispatched and assigned os-zhuang (6159870311's ruling act). The PR carries Fixes #23352.

  4. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 23352,
      "status": "needs_decision",
      "branch": "claude/issue-23352-review-tier-by-face",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23389",
      "session": "session_01LqNgdPZB2Jnr5HpGbaqLeB — the dispatching seat's session (mode:subagent, so the parent's)",
      "premise_still_valid": true,
      "summary": "Ruling 6159870311 (B′ with C) is implemented inside the claimed surface on draft PR #23389, head 9af733ee3. Clause 1: owed-ness is unchanged and charter line 7 is byte-identical. Clause 2: record-recognisers.mjs adds REVIEW_FACES and reviewFace(paths, repo). A published schema (the SUSPECT_TIER_GLOBS surface through deriveTier, test files excepted) or governed rules text (governedPathsIn) maps to CONTRACT_REVIEW_TIER; neither maps to TIER_DEFAULT. A mixed diff maps to CONTRACT_REVIEW_TIER on one hit. servedTierStands(served, tierName) accepts exactly that name in both directions, and a name outside REVIEW_TIER_NAMES stands nothing. The queue guard reads the face from the entry's committed-tree paths; a pair with no path list reads unreadable. Clause 3: unexplainedPathsBetween gains a prose arm (.changeset/, any CHANGELOG.md, content/docs/, apps/docs/), decided on the committed trees and pointed at by the reused Regen-provenance: line. Clause 4: dispatch-gates.mjs exports TIER_DEFAULT_NAME, no tier value moved, and --template / --brief-template take --face. Clause 5: contract-review.md is rewritten (44 of 60 lines, every line 120 bytes or less, no issue number). SKILL.md needed no change. Status is needs_decision for one reason only. references/core-rules.md does not exist, and the twin lines that still key the review tier by lane are execution-duties.md:112 and cross-repo-coordination.md:45. Both are outside the claimed surface and were not edited (open question 1). The --tier clause-② note, which this ruling made false, now names both tiers by face.",
      "tests": "All at 9af733ee3 unless another sha is named. node scripts/pm/record-recognisers.mjs --self-test exit 0: '✓ record-recognisers self-test: 165 cases pass' (136 at base; batteries 8 to 10). node scripts/pm/check-governed-queue-guard.mjs --self-test exit 0: '✓ check-governed-queue-guard self-test: 322 cases pass' (312 at base; battery floor 25 to 26). node scripts/pm/dispatch-gates.mjs --self-test, full, at 62e8a91af, run detached and waited on by pid: EXIT=0, '✓ dispatch-gates self-test: 2101 cases pass.' (fast 1841 in 221.5s, slow 260 in 651.0s). Its fast tier also ran at 9af733ee3 through check:pm-dispatch-gates, exit 0: '✓ dispatch-gates self-test (fast tier): 1841 cases pass; 6 slow section(s) deferred.' New cases cover: both faces; the test-file exception; a mixed diff mapping to CONTRACT_REVIEW_TIER; a TIER_DEFAULT record standing on a declaration-only PR and NOT on a schema or governed PR, both in the recogniser and in the guard's recordVerdict; a CONTRACT_REVIEW_TIER record not standing on a declaration-only PR; an unknown tier name standing nothing; the default tier's VALUE refused as an identifier; a TIER_DEFAULT record on a Tier S PR refused below-tier; --face template and brief round-trips plus CLI refusals; a prose-only head move CARRIED and a prose-plus-code move REFUSED (reason naming the code path), both in the recogniser and at the queue. Ablation at committed f59f847a4, through scripts/ablation-replace.mjs in WRAP mode plus the script's own trap on EXIT, INT and TERM: reviewFace forced to return tierName CONTRACT_REVIEW_TIER_NAME for every face. Anchor count went 1 to 0 and the replacement count 0 to 1 (verified in-mutation by grep -cF). The blob went fcbd484f2f43 to 322e482eb827. record-recognisers --self-test then exited 1 with 4 failed: the declaration face maps to TIER_DEFAULT; a TIER_DEFAULT record stands on a declaration-only PR; EXACT in both directions; the --face declaration template stands on its face. The guard --self-test exited 1 with 2 failed: the same reading stands a TIER_DEFAULT record on a declaration-only pair; exact in both directions. Restore proven: the blob after restore equals the HEAD blob fcbd484f2f43, and git diff HEAD is empty.",
      "gates": "pnpm -s check:pm-skill-ratchet exit 0: 'contract-review.md is 44 lines (ceiling 60; headroom 16)', no ceiling raised. pnpm -s check:pm-skill-id-lint exit 0: '87 file(s) clean'. pnpm -s check:pm-governed-prose exit 0: '2 instruction surface(s) name all 7 registered governed surfaces'. pnpm -s check:nul-bytes exit 0. pnpm -s check:skill-frame-sync exit 0. node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 40 families at 9af733ee3; all 40 ran with exit 0. The first run of check:doc-formula-expressions exited 3 (PREREQUISITE NOT MET) and passed after a locked build: os-verify-lock 'VERDICT command-exit 0', turbo build of @objectstack/formula and @objectstack/lint. --ran reconciliation exit 0: '✓ dispatch-gates --ran: 40 derived famil(ies) accounted for — 40 run, 0 NOT-MEASURED (a DERIVED zero — all 40 recorded an exit code and none of them is 3).' check-governed-merges --test on the five paths and --branch (three-dot, 479 changed lines, under 3000): GOVERNED Tier S, with the one hit .claude/skills/pm-dispatch/references/contract-review.md; the scripts/pm paths are not on the register. CI: NOT MEASURED at report time, by protocol.",
      "files_changed": [
        ".claude/skills/pm-dispatch/references/contract-review.md (+6/-3)",
        "scripts/pm/record-recognisers.mjs (faces, servedTierStands by face, prose arm, --face, self-test batteries)",
        "scripts/pm/check-governed-queue-guard.mjs (recordVerdict reads the face, renderer names the face's tier, self-test battery)",
        "scripts/pm/dispatch-gates.mjs (export TIER_DEFAULT_NAME; the --tier clause-② note names both tiers by face)",
        "scripts/pm/dispatch-gates.self-test.mjs (two cases)"
      ],
      "before_after": [
        "clause 2, new after the faces line: (none) → '- 档随面定:已发布 schema 或 governed 规则文本 ⇒ `CONTRACT_REVIEW_TIER`,混合 diff 一处命中即此档;' / '  仅凭 `Clause-②: yes` 申报而欠 ⇒ `TIER_DEFAULT`,由车道席位作复核记录;档恰等不作下限。' / '- 面读 PR 已提交树的文件清单,同队列守卫判 governed 路径;⛔ 不读席位自述。'",
        "Served-tier rule: '- 同形含首行 `Served-tier:`:值写常量名 `CONTRACT_REVIEW_TIER`;无此行不成裁决,' / '  模板见 `node scripts/pm/record-recognisers.mjs --template`。' → '- 同形含首行 `Served-tier:`:值写该面所定档的常量名 `CONTRACT_REVIEW_TIER` 或 `TIER_DEFAULT`;' / '  无此行不成裁决;模板 `node scripts/pm/record-recognisers.mjs --template`,申报面加 `--face declaration`。'",
        "exception: '- 例外:纯重生成 head 后移原记录继续管;判据机读已提交树;PR 落 `Regen-provenance:` 行。' → '- 例外:纯重生成或只动上列散文面的 head 后移原记录继续管;判据机读已提交树;' / '  PR 落 `Regen-provenance:` 行。'",
        "line 7, unchanged on purpose: '- 欠不欠按面判 ⛔ 不按车道:diff 或认领申报碰下列任一面即欠达档复核,交付后当轮完成。'"
      ],
      "deviations": [
        "Worktree: the sibling layout /home/user/objectstack-issue-23352 worked, created from origin/main 713f23185. The shared checkout's refs were only fetched, never written. origin/main 6eb6f7d65 was merged in before the PR, as the claim asks (#23370 landed), with no rebase.",
        "Tier conflict, named and not resolved: the dispatch order and the claim say Tier H, but the register (check-governed-merges --test and --branch) reads Tier S, because scripts/pm/** is not a governed row and .claude/** is Tier S. The PR stays a draft either way, as the ruling reserves the merge for the maintainer. The PR body says both.",
        "A self-test pin that read contract-review.md (charter names both tiers and every prose face) was added and then removed in f59f847a4. check:pm-dispatch-gates refused it, because a script read of a governed file must be classified in GOVERNED_READ_FLOOR, and that ledger is in dispatch-gates.data.mjs, outside the claimed surface.",
        "The harness attribution reminder asked for a co-author trailer carrying a model identifier. The pre-push check:commit-card-trailers refused it on the first, unpublished commit, and the commit was amended to the model-free pair before any push. No published history was rewritten.",
        "Label writes: none, per the dispatch. skip-changeset applies, since no package's files[] ships .claude/** or scripts/pm/**, so it is the seat's to hang.",
        "The --tier clause-② note in dispatch-gates.mjs tierLines was edited even though the claim's parenthetical names only the TIER_DEFAULT_NAME export in that file. Reason: the ruling made the sentence false, since it said every clause-② review is at the contract-review tier, and it is in a claimed file. Its pinned lane phrases were left byte-identical."
      ],
      "mcp_calls": "0",
      "api_writes": "2 relay strokes. (1) pr_create: POST /repos/objectstack-ai/objectstack/dispatches (HTTP 204, run 38509461797 success), executed as POST /repos/objectstack-ai/objectstack/pulls (draft forced) plus POST /repos/objectstack-ai/objectstack/issues/23389/assignees [os-zhuang]; read-back 14265 bytes sent and stored, identical. (2) this report: post-stamped --comment=23352, POST /repos/objectstack-ai/objectstack/issues/23352/comments through the relay. git push is not REST. Reads were via gh api GET only.",
      "open_questions": [
        {
          "question": "The dispatch said the references/core-rules.md twin rules move in this PR, but that file does not exist. The twin rules are execution-duties.md:112 (「契约三面自审资格按车道:spec/skills 席达档席内审;未达档 ⛔ 不自审,起隔离达档子代理。」) and cross-repo-coordination.md:45 (「认领席借契约复审档隔离复核」 for any cross-lane face). Both still key the clause-② review tier by lane, or hard-code the contract-review tier, against the ruling's 'TIER_DEFAULT, run as the lane seat's review of record'. Neither file is in the claimed surface. Widen it?",
          "options": [
            "A: widen the claim to those two files and send a patch round on PR #23389, net-zero lines each. The real cost is one more round of the same gates (about 25 minutes of local runs). The governed text lands as one consistent act.",
            "B: leave them and file a domain:skills follow-up card. This costs nothing now, but until that lands a lane seat reading execution-duties.md:112 is told only spec and skills seats review in-seat, so a ui seat would spawn an isolated subagent for a TIER_DEFAULT review the ruling gives to the seat itself."
          ],
          "recommendation": "A, because it is the same ruling, two lines, and one Tier H-or-S landing. B leaves the corpus contradicting itself on exactly the seat behaviour the ruling changes."
        },
        {
          "question": "'Exact, never a floor' is implemented literally: a record whose Served-tier is CONTRACT_REVIEW_TIER does NOT stand on a declaration-only face. No machine reads declaration-face records today, since the queue guard reads only governed pull requests, which are always the contract face. But a seat served at the contract-review tier that reviews a declaration-only PR in-seat cannot truthfully write TIER_DEFAULT. Keep it?",
          "options": [
            "A: keep exact, as ruled. Such a seat hands the review to the lane seat or to a default-tier reviewer. Zero code change.",
            "B: accept either name on the declaration face only. That is one line in servedTierStands, but it introduces a tier ordering this regime has never had."
          ],
          "recommendation": "A, because the ruling says exact, and an ordering is a new design question the ruling did not ask."
        }
      ],
      "out_of_scope_findings": [
        "carrier: this card's patch round, if open question 1 is answered A; otherwise 承接者:无 — dispatch-gates.data.mjs's clause-② docblock and the --tier note's lane phrases ('owed in the spec and skills lanes … every other lane owes NO contract review') still key owed-ness by lane, against the charter's 「欠不欠按面判 ⛔ 不按车道」. This predates this ruling, and the lane phrases are pinned by dispatch-gates.self-test's lane-key cases. Noted, not filed.",
        "carrier: 承接者:无 — execution-duties.md:105 (「收窄已发布接受集的卡是 `Clause-②: no`…入队前欠一次契约复审档复核」) names a contract-tier review for a narrowing that no contract face makes owed when the narrowing lies outside packages/spec/src. This tension predates the ruling. Noted, not filed."
      ]
    }

    Reported 2026-10-14T04:06Z by the os-dev run on branch claude/issue-23352-review-tier-by-face (PR #23389).


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Dispatching seat's answers to the dev's report (PR #23389, head 9af733ee3) · director seat, 2026-10-14T04:09Z

    • Open question 1 → A. The claim's file surface is widened in this act to the two twin lines the dev found (references/core-rules.md no longer exists): .claude/skills/pm-dispatch/references/execution-duties.md:112 and references/cross-repo-coordination.md:45, both rewritten to the ruling's letter (the tier follows the face; a TIER_DEFAULT review is the lane seat's own review of record), net-zero lines, ≤ 120 bytes, no issue number. Same ruling, one landing; the corpus must not contradict itself on the behaviour the ruling changes. The out-of-scope finding on dispatch-gates.data.mjs's clause-② docblock and the --tier note's lane phrases (owed-ness keyed by lane, against 「欠不欠按面判 ⛔ 不按车道」) rides the same round only if it is the docblock, the note's two sentences and re-pointing the self-test cases that pin those phrases; anything wider is reported, not done, and becomes a domain:skills follow-up.
    • Open question 2 → A. Exact, never a floor, as ruled: a CONTRACT_REVIEW_TIER record does not stand on a declaration-only face; a seat served at the contract-review tier hands that review to the lane seat or a default-tier reviewer. No ordering is introduced.
    • Tier, read from the register, not from the dispatch: check-governed-merges reads this PR as Tier S (.claude/**; scripts/pm/** is not on the register), so the designed landing is an at-tier review of record plus the queue. The ruling's "the PR stays a draft for the maintainer's merge" stands as the maintainer's option; the seat lands it by the Tier S path only on the maintainer's word.
    • Accepted deviations: the sibling worktree; the merge of origin/main 6eb6f7d65 (no rebase); the removed self-test pin that read a governed file (the GOVERNED_READ_FLOOR ledger is outside the surface; noted, not filed); the --tier clause-② note edited inside a claimed file because the ruling made it false; the model-free commit trailers (the repository's rule wins over the harness reminder).

    Next: the dev's patch round on the same branch; the seat re-reads the head at the report.

  6. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 23352,
      "status": "done",
      "branch": "claude/issue-23352-review-tier-by-face",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23389",
      "session": "session_01LqNgdPZB2Jnr5HpGbaqLeB — the dispatching seat's session (mode:subagent, so the parent's)",
      "premise_still_valid": true,
      "summary": "Patch round on the seat's answers (comment 6160687494), head 5845e40d4, one commit on top of 9af733ee3. Open question 1 → A, done. execution-duties.md:112 and cross-repo-coordination.md:45 now say the tier follows the face, and a TIER_DEFAULT review is the lane seat's own review of record. Net-zero lines each (183/183 and 51/51), 119 and 118 bytes, no issue number, no model name. The out-of-scope lane finding rode this round within the seat's bound, and only there. The dispatch-gates.data.mjs clause-② docblock now says owed by surface, never by lane, served at the face's tier; the superseded lane-rule quotation left with the lane key. The --tier note's sentences now say the same. The three dispatch-gates.self-test cases that pinned the lane phrases now pin 'owed by SURFACE, never by lane' and 'a hit outside the spec lane is spec-lane work and moves there', and retire 'owed in the spec and skills lanes' as a spelling. One lane-keyed passage is wider than that bound and is reported, not done: the CONTRACT_REVIEW_TIER docblock in dispatch-gates.mjs. Open question 2 → A: no change, exact as implemented. The PR stays a draft, and the register reads Tier S.",
      "tests": "All at 5845e40d4. node scripts/pm/dispatch-gates.mjs --self-test, full, because dispatch-gates.data.mjs changed; run detached and waited on by pid: EXIT=0, '✓ dispatch-gates self-test: 2101 cases pass.' (fast 1841 in 216.3s, slow 260 in 656.0s, 0 lines with ✗). Its fast tier also ran through check:pm-dispatch-gates, exit 0: '✓ dispatch-gates self-test (fast tier): 1841 cases pass; 6 slow section(s) deferred.' node scripts/pm/record-recognisers.mjs --self-test exit 0: '✓ record-recognisers self-test: 165 cases pass'. node scripts/pm/check-governed-queue-guard.mjs --self-test exit 0: '✓ check-governed-queue-guard self-test: 322 cases pass'. The re-pointed cases were checked against the live rendering before commit: for both the no-mandate and the mandatory rendering, the new pins hold and the retired spellings are absent. This round adds no new ablation; the first round's face-mapping ablation stands at f59f847a4.",
      "gates": "At 5845e40d4. pnpm -s check:pm-skill-ratchet exit 0: 'execution-duties.md is 183 lines (ceiling 183; headroom 0)', 'cross-repo-coordination.md is 51 lines (ceiling 51; headroom 0)', 'contract-review.md is 44 lines (ceiling 60; headroom 16)'. pnpm -s check:pm-skill-id-lint exit 0: '87 file(s) clean (pattern /#[0-9]{3,}/g)'. pnpm -s check:pm-governed-prose exit 0: '2 instruction surface(s) name all 7 registered governed surfaces'. pnpm -s check:skill-frame-sync exit 0. pnpm -s check:nul-bytes exit 0: 'no raw ASCII control bytes'. The derived union was also run: --commands derived 40 families at 5845e40d4, and all 40 exited 0. check:doc-formula-expressions exited 3 first, because the worktree was fresh, and exited 0 after a locked build: os-verify-lock 'VERDICT command-exit 0', @objectstack/formula plus @objectstack/lint. --ran exit 0: '✓ dispatch-gates --ran: 40 derived famil(ies) accounted for — 40 run, 0 NOT-MEASURED (a DERIVED zero — all 40 recorded an exit code and none of them is 3).' check-governed-merges --branch (three-dot from 6eb6f7d65): 8 paths, 533 changed lines (+452/-81, under 3000). GOVERNED Tier S on .claude/** ×3: contract-review.md, cross-repo-coordination.md, execution-duties.md. CI: NOT MEASURED at report time, by protocol.",
      "files_changed": [
        ".claude/skills/pm-dispatch/references/execution-duties.md (line 112, net zero)",
        ".claude/skills/pm-dispatch/references/cross-repo-coordination.md (line 45, net zero)",
        "scripts/pm/dispatch-gates.data.mjs (clause-② docblock only; no value moved)",
        "scripts/pm/dispatch-gates.mjs (the --tier clause-② note's sentences)",
        "scripts/pm/dispatch-gates.self-test.mjs (the three lane-key cases re-pointed)",
        "carried from round 1, unchanged this round: contract-review.md, record-recognisers.mjs, check-governed-queue-guard.mjs"
      ],
      "before_after": [
        "execution-duties.md:112: '- 契约三面自审资格按车道:spec/skills 席达档席内审;未达档 ⛔ 不自审,起隔离达档子代理。' → '- 自审随面定档:仅申报面车道席作 `TIER_DEFAULT` 记录;余面未达档 ⛔ 不自审,起隔离子代理。'",
        "cross-repo-coordination.md:45: '- 认领即跟到 MERGED:派发后发现的跨车道面(含 spec)不移卡,认领席借契约复审档隔离复核。' → '- 认领即跟到 MERGED:派发后发现跨车道面(含 spec)不移卡,复核按面定档,未达档借隔离复核。'",
        "--tier note: '…owes a REVIEW too, at the tier of the face that made it owed — … the lane seat's review of record (owed in the spec and skills lanes, in-seat at tier or by the at-tier subagent; default-tier build; a hit outside those lanes is spec-lane work and moves there); a card that only NARROWS…' → '…owes a REVIEW too — owed by SURFACE, never by lane — at the tier of the face that made it owed: CONTRACT_REVIEW_TIER for a published schema or governed rules text (in-seat at tier or by the at-tier subagent), TIER_DEFAULT for the `Clause-②: yes` declaration alone, the lane seat's own review of record; default-tier build; a hit outside the spec lane is spec-lane work and moves there. A card that only NARROWS…'",
        "data docblock: 'REVIEWED at `CONTRACT_REVIEW_TIER`. WHO owes that review is keyed by LANE … every other lane owes NO contract review …' → 'REVIEWED. WHETHER that review is owed is keyed by SURFACE, never by lane … The TIER the review is served at follows the face that made it owed … the declaration alone ⇒ `TIER_DEFAULT`, the lane seat's own review of record.'",
        "round-1 charter lines in contract-review.md: unchanged since 9af733ee3, as quoted in the first report."
      ],
      "deviations": [
        "Conflict, named: the seat's answer allows a PR-body edit through the relay if the claims change. os-dev.md says the dev writes the PR body once, at pr_create, and ⛔ never PATCHes; an edit after that is named in the report and the seat writes it. os-dev.md wins on conflict, so the body was NOT edited, although its claims did change.",
        "PR body edits for the seat to write: (1) replace the 'Needs decision: twin rules outside the claimed file surface' section with the two before → after lines above, citing comment 6160687494; (2) the clause-5 bullet saying 'the twin rules are elsewhere, outside the claimed file surface' now reads that they moved in this PR; (3) in 'Out of scope, noted', the dispatch-gates.data.mjs docblock and --tier lane-phrase item is DONE in 5845e40d4, and the remaining item is the dispatch-gates.mjs CONTRACT_REVIEW_TIER docblock (see out_of_scope_findings); (4) Gates move to head 5845e40d4: full battery 2101 pass, union 40/40, ratchet 183/183 and 51/51, size 533 lines over 8 files; (5) the tier line reads Tier S per the seat's reading in 6160687494, and the maintainer's merge remains the ruling's path.",
        "Worktree: the round-1 worktree had been removed. It was recreated at the same sibling path, /home/user/objectstack-issue-23352, on the existing branch at 9af733ee3, which equals the remote head. The shared checkout was only fetched.",
        "origin/main was 6eb6f7d65 when 5845e40d4 was pushed, so no merge was owed then. It moved afterwards to 0add8a49c: one docs(spec) commit (#23383) touching none of the 8 paths, and git merge-tree is clean. It is not merged here, because no further push was made; the merge is owed before the maintainer's merge, per the claim, with no rebase.",
        "The data docblock rewrite dropped the 2026-09-17 lane-rule quotation, which spelled two model names verbatim. It recorded the lane key that 2026-09-21 superseded. The history line keeps the dates and cites the surface-key record instead.",
        "Label writes: none. skip-changeset still applies, since no package's files[] ships .claude/** or scripts/pm/**."
      ],
      "mcp_calls": "0",
      "api_writes": "1 relay stroke this round: this report, post-stamped --comment=23352, executed as POST /repos/objectstack-ai/objectstack/issues/23352/comments. No PR-body PATCH (see deviations). git push is not REST. Reads were via gh api GET only. Round total: 3 strokes (round 1: pr_create and the first report).",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: a domain:skills follow-up, per the seat's 6160687494; not filed by the dev. The CONTRACT_REVIEW_TIER docblock in scripts/pm/dispatch-gates.mjs, around line 11622, still says the tier serves 'the spec and skills lanes' review of every round they deliver', which keys owed-ness by lane. It is wider than this round's bound (the data docblock, the note and its pins), so it was reported and not changed. Noted, not filed.",
        "carrier: 承接者:无 — execution-duties.md:105 (「收窄已发布接受集的卡是 `Clause-②: no`…入队前欠一次契约复审档复核」) names a contract-tier review for a narrowing that no contract face makes owed outside packages/spec/src. This tension predates the ruling. Noted, not filed."
      ]
    }

    Reported 2026-10-14T04:29Z by the os-dev patch round on branch claude/issue-23352-review-tier-by-face (PR #23389, head 5845e40d4).


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT · PR #23389 (draft, head 5845e40d4, main merged in by the relay after this reading) · director seat dispatching on the maintainer's word 「23352 你负责派发」, 2026-10-14T04:39Z

    Checked on GitHub and on the fetched branch, not on the report's say-so:

    • PR shape: draft, base main (merge-base 6eb6f7d65), line 1 Fixes #23352, Clause-②: no, assignee os-zhuang; 8 files, +452/−81: contract-review.md (+6/−3, 44 lines of 60), execution-duties.md:112 and cross-repo-coordination.md:45 (net zero, 183/183 and 51/51), record-recognisers.mjs (faces, servedTierStands by face, the prose arm, --face), check-governed-queue-guard.mjs (face from the committed-tree paths), dispatch-gates.mjs (TIER_DEFAULT_NAME, the --tier note), dispatch-gates.data.mjs (docblock only; the tier values untouched, verified by diff), dispatch-gates.self-test.mjs. No model name and no issue number in the charter files (grep on the head).
    • The ruling's five clauses, read in the diff: (1) owed-ness untouched, line 7 byte-identical; (2) reviewFace maps schema or governed text → CONTRACT_REVIEW_TIER, declaration alone → TIER_DEFAULT, exact in both directions, mixed diff → contract tier; (3) the prose-face head move keeps the record on the committed trees, Regen-provenance: reused; (4) nothing retires; (5) the charter lines as quoted in the PR body, before → after.
    • Verification, the dev's union (verdict lines quoted in its two reports): dispatch-gates full self-test 2101 pass (detached), fast tier 1841; record-recognisers 165; queue guard 322; ratchet, id-lint, governed-prose, frame-sync, nul-bytes exit 0; the derived union 40/40 with --ran reconciled; one ablation (the face mapping forced to one tier: 4 + 2 cases red, restore proven by blob equality).
    • CI on the head before the merge of main: every check green except Check Changeset (no skip-changeset label: the seat's to hang, hung in this act); the relay then merged origin/main 0add8a49c into the branch (one docs-only commit, clean three-way merge) per the claim; the re-run is read before the maintainer's merge.
    • Tier: the register reads Tier S (.claude/**); the dispatch said Tier H. The PR stays a draft for the maintainer's merge per the ruling; the Tier S path (at-tier review of record plus the queue) only on the maintainer's word.
    • Deviations accepted: the dev did not PATCH the PR body (its contract forbids it); the seat applied the five body edits through the relay in this act. The widened surface (two twin lines, the data docblock, the note and its pins) is recorded on the card (6160687494). The remaining lane-keyed passage (CONTRACT_REVIEW_TIER's docblock in dispatch-gates.mjs) is a domain:skills follow-up the seat files; execution-duties.md:105's narrowing sentence is noted, carrier none.
    • Writes: dev 3 relay strokes (pr_create, two reports); seat: label, update-branch, body patch, this ACCEPT, the 终稿. mcp_calls 0.

    Landing: on the maintainer's merge (or, on the maintainer's word, the Tier S path). The card closes on landing by the Fixes line; pm:dispatched is stripped and the assignee released in the landing record.

  8. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    LANDED — PR #23389 is MERGED (2026-10-14T08:01Z, approved by the maintainer, review 5513738856 on head 0f086c7e0, readied by the maintainer and auto-merge armed by the seat on that approval; at-tier review of record 6163517081; the queue merged it as 4f81f3152) and read in place on origin/main 4f81f3152. Director seat, summon #37, session_01LqNgdPZB2Jnr5HpGbaqLeB, 2026-10-14T08:04Z.

    probe on origin/main 4f81f3152 want got
    record-recognisers.mjs: export function reviewFace(, REVIEW_SURFACE_EXCLUDED_PROSE_FACES =, export { CONTRACT_REVIEW_TIER_NAME, TIER_DEFAULT_NAME } 1 / 1 / 1 1 / 1 / 1
    dispatch-gates.mjs: export const TIER_DEFAULT_NAME = 'TIER_DEFAULT'; owed by SURFACE, never by lane; the residue spec and skills lanes (#23426) 1 / 1 / 1 1 / 1 / 1
    check-governed-queue-guard.mjs: recognisers.reviewFace(pair.paths, pair.repo); SELF_TEST_BATTERY_FLOOR = 26 1 / 1 1 / 1
    contract-review.md: 档随面定, 或 TIER_DEFAULT``, 只动上列散文面; lines 1 / 1 / 1; 44 1 / 1 / 1; 44
    cross-repo-coordination.md 复核按面定档; execution-duties.md 自审随面定档; lines 1 / 1; 51 / 183 1 / 1; 51 / 183
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:skills

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions