feat(pm): a class-(b) finding names its seam — the Seam: line on os-dev.md rule 3, and the H68 patrol row for a (b) card without one - #19356
Conversation
…-dev.md rule 3, and the H68 patrol row for a (b) card without one os-dev.md 六条基本规则 3 (net 0 on 403 / 403): the (b) line gains 「带 `Seam:` 行」 and ONE adjacent line carries the grammar — `Seam: spec:KEY → runtime:CALL_SITE | renderer:COMPONENT`, `consumer: none` when no consumer was measured. Paid by retiring the MCP-write/token line, whose ban survives at the REST-only line, the label-write clauses and the report template's `mcp_calls` field, and whose token→login fact lives in pm-dispatch references/platform-readings.md. check-half-states.mjs: H68 — an OPEN card that DECLARES class (b) in its body (a heading naming the class or a line opening with it, the shapes measured on the live board) and carries no `Seam:` line at line start, read with the directive reader `Blocked-by:` shares. Report-only, `state` band, the unscoped listing (H63's channel), no request. Battery beside H63's cases; SELF_TEST_BATTERY_FLOOR 6 → 7. Claude-Session: https://claude.ai/code/session_017ETYWqMQD4qMtZzAGovWNi Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: ① Derived judgments
② Semver levelNone — nothing published; ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
… self-test roster carries both new batteries The label-transition unlock-exit battery landed on main while this branch was open; both sides raised SELF_TEST_BATTERY_FLOOR 6 → 7 and added a roster row at the same place. Resolved by the seat as the claim's rule says the later lander does: both rows kept, the floor set to 8, and every floor pin (the four batteries that count the roster) moved to EIGHT. Self-test: 5118 cases, 8 batteries. Claude-Session: https://claude.ai/code/session_017ETYWqMQD4qMtZzAGovWNi Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: ① Derived judgments
② Semver levelNone — unchanged from 5750369816; ③ Boundary flagsUnchanged from 5750369816, plus: the roster resolution is the seat's own commit on the dev's branch — a base merge with conflict resolution, the one seat-side write the claim's rule provides for; CI re-runs on this head and the queue entry follows a green run. Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #18901
Clause-②: no
Ruling-ref: 5727134819 — director seat batch #157 item 3, letter A′ on #18900 (item ①, this card, as filed); triage handover 5725479658 binds (every governed text at its ceiling; the retired line is named below).
Seat
domain:skills#2· claim 5749402494 · branchclaude/issue-18901-seam-line-filing-rule· head5033c4d(onorigin/main13d5294).What lands
1.
.claude/agents/os-dev.md六条基本规则 3 — net 0 (403 / 403), every touched line under the 120 B line ratchetSeam:行);」Seam: spec:KEY → runtime:CALL_SITE | renderer:COMPONENT, then 「,无消费者写consumer: none。」 — in the file the three placeholders are written in Chinese inside ASCII angle brackets (键或符号 / 调用点 / 组件), spelled out here as words because this body is a GitHub body.13d5294(115 B): 「 - ⛔ 不用 MCP GitHub 写工具;令牌按会话定:installation ⇒claude[bot],user-to-server ⇒ 用户。」 Surviving homes, clause by clause: the ban lives on :51 「GitHub 写一律走 REST 代理(curl带GITHUB_TOKEN)」 (all writes REST ⇒ no MCP write), :307 「不走 MCP」, :308 「⛔ 不换路重发(curl/MCP/手工)」 and the report template :371mcp_calls「a write tool in the list = this report is refused」; the token → login fact lives at.claude/skills/pm-dispatch/references/platform-readings.md:130「容器 curl 的 REST 通道令牌两类:installation(claude[bot])与 user-to-server(用户)」, and the rule that fact served — 「归属 = 文本里的 session ID,非user.login」 — stays on :51. Line numbers are pre-edit; after the edit the REST line is :52 and :307 / :308 / :371 are unchanged (one insert and one delete above them cancel). No gate pins the retired line's phrases (greppedscripts/,.claude/,.github/).Seam:card routes by the seam — vertical dispatch by default inside objectstack (file surface names both ends; acceptance = the consumer reads it or the key retires with its ledger row), and rule 2's parent + per-repo sub-issues trigger on a spec↔objectui seam, not only on a feature (item ② of #18900) #18902, in flight on this seat): the key is backtickedSeam:in both texts.2.
scripts/pm/check-half-states.mjs— H68, ONE report-only row, net +120 (124 insertions / 4 deletions)h68ClassBWithoutSeamLine(issue)with its docblock, placed after H63's; readersclassBDeclaration(body)— a markdown heading naming the class, or a line opening with it (list / quote / bold decoration and a leadingFindingtolerated), the shapes measured below — andhasSeamLine(text)=directiveValues(text, 'Seam'), the readerBlocked-by:/Restart-when:share (decoration tolerated, a same-line value required, a bare key with nothing after it is no line).state, registered beside H67 with the three refusals argued (familyRegistryCoverage: 0 missing / 0 extra; registry 62 / cap 64).findingcarrier is first visible there; two body reads on a row already held, no request, no thread.H68 class-(b) seam linebeside H63's cases (26 registered, pin 24; ⛔ not atselfTest()'s tail);SELF_TEST_BATTERY_FLOOR6 → 7 with the three existing exact pins moved.markerMatches, the H26 region ([finding] a pm:blocked card whose Blocked-by target is a needs-user-decision card can never be released — the unlock predicate is "closed", and Unlock-action recognizes exactly one PR-shaped spelling #19255), every workflow file, anddirectiveValues's JSDockeyunion (that line sits in [finding] a pm:blocked card whose Blocked-by target is a needs-user-decision card can never be released — the unlock predicate is "closed", and Unlock-action recognizes exactly one PR-shaped spelling #19255's hunk; the reader is untyped at runtime).Seam:is deliberately not judged here — presence at line start is the filed contract; the value is the routing half's reading.The class-(b) signal, measured (board read 2026-09-20T11:12Z, 537 open non-PR cards, saved listing replayed against the finished row)
class (b)/判据 (b)anywhere: 20. DECLARING it — a heading naming the class (## Class (b) — …,## Why it is class (b),## The defect — class (b), …,## 判据 (b):…) or a line opening with it (Class (b): …,**Class (b)** — …,⇒ class (b): …,Finding class (b), …): 16, one of them thepm:seatpost [PM seat] triage (objectstack-wide) — 🟢 session_01KYzNJPin9Ar4oMMkSh4S9h · 就座 2026-09-20 · 自绑 Routine trig_016NBra1kZGHk7UteTziFbrK · ⛔ 接手先读正文「大扫除试运行班收班交接台账」再定级 #6015 (never judged) ⇒ 15 listable. Mid-sentence only: 4 — finding(spec): the react-tierListViewcatalogue declaresonNavigate's action as'view' | 'edit'— the implementation sendsviewandnew_window, andeditzero times #19030, [finding]@objectstack/spechas four grammars for a packageversion, andManifestSchemarefuses the2.0.0-beta.1thatPackageVersionSchema's own docstring advertises #18697, [finding] the tracked rootsdui.manifest.jsonand the browser dump differ on the fields the parity gate consumes (18 of 57 components;dataSourcemissing on 15 in the root artefact) — the gate's verdict set is identical under both today, which is the configuration in which the drift is least visible #17735 and os-dev's three-class filing rule: a class-(b) finding names its seam — aSeam:line (producer → consumer,consumer: noneallowed) on the card, and the half-state patrol reports a class-(b) card that lacks one (item ① of #18900) #18901, this card, which is ABOUT the rule and is the false positive a mention-reader would list.findingcards 20 (5 withdomain:*, 6 with any comment) — a comment naming the class on 0 of 20; on the 20 body hits, 8 also carry such a comment; comment-only cards: 0. The body declaration strictly dominates and costs no request ⇒ the row reads the body only; the comment channel is not read.Seam:at line start on the whole open board: 0 (6 cards mentionSeam:, all about the rule) — every (b) card listed today predates the rule, which is the population the routing half needs the line on.max_scalehas no percent arm and thepercentScaleOfdocblock is silent aboutscale#19320 [finding] the duplicate-name refusal onsys_permission_setcarries NO machine-readablecode— a bare 409, and it fires BEFORE the packaged-set guard, so the Clone dialog's most likely error never reachesNOT_OVERRIDABLE#19307 [finding] 退役的GIT_*allowlist 还有第三个载体 ——create-objectstack/src/template-consistency.test.ts,分诊 2026-09-08 的普查只点了两个 #19171 finding(scripts/pm): H52 has no clearing act on apm:on-holdcard — the only three null-exits are close,needs-user-decision(which the row itself forbids here) and a newer dev report a held card can never get #19160 skills(pm-dispatch): grading reads the checklist ITEM, not the area —Path:carries the item id, the card inherits the item's P, and 「有人在等」 is not a test #19155 skills: re-key the three 事实层 = references/ spellings the Tier S ruling leaves false (os-dev.md :286–:287, landing-operations.md :27–:28, H48) #19146 [finding] check-doc-authoring 的两条腿都够不到 packages/spec/scripts/** —— 一条印给作者的拒绝消息里带着 404 的编号,而门禁是绿的 #19124 [finding] POST /api/v1/packages installs a manifest with NO version and answers 201, while its published declaration requires one — the door parses nothing #19120 [finding] a key retired through the .strict() guidance-map route leaves no [REMOVED] tombstone — the whole route is invisible to the ledger and to every walk-rooted census, and nothing says so #19118 [finding] the ownership near-miss census still listsRelease-landed: …report-line labels as refused release records — fourseparatorlines on two cards, the largest remaining class of the kind #18926 narrowed #19043 finding(skills): the seat's claim-time serial check reads open PRs' file lists only, so a sibling card already claimed and pushed but not yet opened as a PR is invisible to it — onegit ls-remote --heads origin | grep <file stem>would have shown #18314's branch before #18844 was claimed #18964 finding(skills):dispatch-runbook.md:61 paraphrases reading three NARROWER than SKILL.md :80 declares — it drops∪ pm:queueand 同席号, so a seat following the runbook can miss aClaim:on apm:queuecard and fail to self-retire (the two-writer seat, by a second route) #18957 [finding] the landing flow has no legal state for the undraft route's 429 — a seat that hits it can only escalate or invent a retry cadence, while the 429 body names the exact instant to wait for #18743 [finding] driver-memory keeps a THIRD refusal wording for the same dateRange condition — the tree is at two wordings, not one, after #18232 #18277 [finding] check (c) has no proof shape for a strict-schema guidance retirement — on a reachable def such a key can never prove itself, and it passed only because proof 2 was broken #18132.pm:on-holdcard — the only three null-exits are close,needs-user-decision(which the row itself forbids here) and a newer dev report a held card can never get #19160 (pm:queue·domain:skills·priority:p2) — 「## Class (b) — it violates a contract this repository publishes」, noSeam:line; the row quotes that heading back.pm:on-holdcard — the only three null-exits are close,needs-user-decision(which the row itself forbids here) and a newer dev report a held card can never get #19160 body withSeam: spec:… → runtime:…appended (a fixture — no live (b) card carries the line; finding(spec):field.relatedListFilterandobject.validationsare DECLARED by the served schema and omitted byMETADATA_FORM_REGISTRY's forms — the generic metadata form never renders them, so an author's only door is the Source tab #19085 is closed and carries neither signal), and os-dev's three-class filing rule: a class-(b) finding names its seam — aSeam:line (producer → consumer,consumer: noneallowed) on the card, and the half-state patrol reports a class-(b) card that lacks one (item ① of #18900) #18901 itself (mid-sentence mention).Reader test
「I found a declared key the runtime never reads — what do I write?」 ⇒ the (b) line — 违背已声明契约(引契约原文,带
Seam:行): cite the contract text and addSeam: spec:THE_KEY → consumer: none(you measured no consumer). Where a consumer exists but does not honour the key:Seam: spec:THE_KEY → runtime:THE_CALL_SITE, orSeam: spec:THE_KEY → renderer:THE_COMPONENT.Verification — all on head
5033c4d, every exit code captured before any pipenode scripts/pm/check-half-states.mjs --self-test→ exit 0 — 「✓ check-half-states self-test: 5107 cases pass. Batteries: H66 released queue card 183/172, H19 judged-set founding 37/34, H65 tier declaration spelling 46/42, H67 queued merged-delivery reading 152/142, H2/H47/H66 decorated ownership marker 213/184, ISSUE_BODY_LIMIT measured cap 55/52, H68 class-(b) seam line 26/24」.pnpm check:pm-skill-ratchet→ exit 0 — 「✓ check-skill-line-ratchet: .claude/agents/os-dev.md is 403 lines (ceiling 403; headroom 0)」.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackat5033c4d(47 commands, no paths passed): 47 / 47 ran on5033c4d, every one exit 0 —--ranreconciliation: 「47 derived famil(ies) accounted for — 47 run, 0 NOT-MEASURED (a DERIVED zero — all 47 recorded an exit code and none of them is 3)」. The list:node scripts/check-changeset-no-major.mjs --base origin/main·node scripts/check-changeset-no-major.mjs --self-test·node scripts/check-ci-filter-parity.mjs·node scripts/check-closing-keyword-parity.mjs·node scripts/check-closing-keyword-parity.mjs --self-test·node scripts/check-comment-mask-corpus.mjs·node scripts/check-declaration-mirrors.mjs·node scripts/check-declaration-mirrors.mjs --self-test·node scripts/check-scripts-symbol-anchors.mjs·node scripts/check-scripts-symbol-anchors.mjs --self-test·node scripts/check-self-test-wired.mjs·node scripts/check-self-test-wired.mjs --self-test·node scripts/check-self-test-workflow-commands.mjs·node scripts/check-self-test-workflow-commands.mjs --self-test·node scripts/check-whole-set-label-write.mjs·node scripts/check-whole-set-label-write.mjs --self-test·node scripts/pm/bare-root-worklist.mjs --self-test·node scripts/pm/board-snapshot.mjs --self-test·node scripts/pm/check-governed-queue-guard.mjs --self-test·node scripts/pm/check-harness-current.mjs --self-test·node scripts/pm/sweep-closed-cards.mjs --self-test·pnpm --filter @objectstack/lint run check:doc-formula-expressions·pnpm check:agent-model-declared·pnpm check:agent-test-spelling·pnpm check:bash32-floor·pnpm check:changeset-gate-self-tests·pnpm check:cli-command-ids·pnpm check:closing-target-claim·pnpm check:commit-card-trailers·pnpm check:cross-package-test-inputs·pnpm check:doc-authoring·pnpm check:driver-memory-census·pnpm check:entry-guard·pnpm check:nul-bytes·pnpm check:parse-guard·pnpm check:partof-closing-keyword·pnpm check:pm-dispatch-gates·pnpm check:pm-governed-merges·pnpm check:pm-half-states·pnpm check:pm-skill-id-lint·pnpm check:pm-skill-ratchet·pnpm check:pnpm-filter-targets·pnpm check:ratchet-remedy-authority·pnpm check:refd-timer-probe·pnpm check:single-claim-paths·pnpm check:skill-frame-sync·pnpm check:watch-hint-literal.node scripts/pm/check-governed-merges.mjs --test .claude/agents/os-dev.md scripts/pm/check-half-states.mjs→ exit 3 = GOVERNED, Tier S (.claude/**×1;scripts/pm/check-half-states.mjsnot on the register) — the expected reading: this PR stays DRAFT until the seat's## Contract reviewrecord for the current head.check:doc-formula-expressions:pnpm --workspace-concurrency=2 --filter '@objectstack/lint...' buildunderscripts/pm/os-verify-lock.sh— 「VERDICT command-exit 0 · held the lock 220s」.Acceptance notes (noted, not filed)
ListViewcatalogue declaresonNavigate's action as'view' | 'edit'— the implementation sendsviewandnew_window, andeditzero times #19030, [finding]@objectstack/spechas four grammars for a packageversion, andManifestSchemarefuses the2.0.0-beta.1thatPackageVersionSchema's own docstring advertises #18697, [finding] the tracked rootsdui.manifest.jsonand the browser dump differ on the fields the parity gate consumes (18 of 57 components;dataSourcemissing on 15 in the root artefact) — the gate's verdict set is identical under both today, which is the configuration in which the drift is least visible #17735) and are deliberately not listed; 承接者: the seat that next grades or writes on each — a heading or line-start restatement puts them on the row.directiveValues's JSDockeyunion does not name'Seam'; 承接者: [finding] a pm:blocked card whose Blocked-by target is a needs-user-decision card can never be released — the unlock predicate is "closed", and Unlock-action recognizes exactly one PR-shaped spelling #19255's lander (one word on a line already in that hunk).SELF_TEST_BATTERY_FLOOR: [finding] a pm:blocked card whose Blocked-by target is a needs-user-decision card can never be released — the unlock predicate is "closed", and Unlock-action recognizes exactly one PR-shaped spelling #19255 (in flight) bumps the same 6 → 7 and adds its own roster row; the later lander resolves the roster merge and sets 8.finding+domain:*(5 cards, none with a class comment) —findingis transient (「定级即离标」, H63), so the measurement ran over the whole open board.维护者速读(草稿)
改了什么:给开发 agent 的立卡规则加了一句:凡是「协议里声明了、运行时或渲染器没兑现」这一类(b 类)发现,卡面上必须带一行机器可读的
Seam:,写明这条缝的两端(哪个协议键 → 哪个运行时调用点或哪个渲染组件;实测没有消费者就写consumer: none)。同时巡检脚本新增一行只报不判的 H68:把已经声明为 b 类却没写这一行的开放卡按编号列出来。文件行数不变(403 / 403),为此退休了一行重复条款(MCP 写工具禁令 + 令牌说明),它的内容在同规则的 REST-only 行、标签写入条款、报告模板和 platform-readings 里都还在。为什么改:你 9-18 同意的五项攒批第 ① 项。今天缝卡按「修复落地的包」路由,缝的两端各落一层、各修一次;有了这一行,路由那一半(#18902)才能按缝派发,一个键在一次落地里要么被兑现要么退役。板面实测:15 张开放 b 类卡今天都没有这一行,巡检会把它们列出来。
风险与代价(含回滚):只加一行规则、一行巡检;不改标签、不写板面、不判红。误报边界已量:句中顺带提到「class (b)」的卡不列(3 张),席位帖子不列。回滚 = revert 本 PR。巡检脚本的行数配额已用满(+120);自测下限 6 → 7,与在飞的 #19255 撞同一行,后落地者改为 8。
席位意见:
你要做的:受管面(
.claude/**,Tier S)⇒ 席内达档复核后由席位落地,不需要你点击。若你希望巡检也校验Seam:行的取值格式(今天只查有没有这一行),回一个字,另立卡。Generated by Claude Code