Skip to content

fix(pm): mailbox doorbell key fields read the seat with seatKey, which refuses reserved domain lane names - #27986

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-sji7vf
Oct 30, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-sji7vf

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Elon · project thread

Fixes #27891

What changes

  • scripts/pm/record-recognisers.mjs: the seven doorbell keys' LANE#N fields (Notify: seat-online, seat-offline, split) are read with seatKey, imported from mailbox-open.mjs. The second, looser seat shape SEAT_REF is deleted. The short form skills#2 is now refused in a key field (unreadable, "does not spell its template"), exactly as it is on the To: line. An absent number reads as seat 1 (triage → triage#1), and the seat reading carries the canonical key beside lane and n.
  • scripts/pm/mailbox-open.mjs: seatKey refuses a domain: lane named after a reserved lane word — domain:triage, domain:director, domain:repo-… — whose slug would be another seat's (triage-1, repo-cloud-1). The lane words are lifted into the exported SEAT_LANE_KINDS and SEAT_BARE_LANES, the one spelling that SEAT_SHAPE and the reserved set are both built from. A name that merely contains a reserved word (domain:triage-tools, domain:directory) still reads.
  • Pins: 4 new cases in the mailbox-open self-test (short form refused, reserved name refused, containing-a-word still reads, the shape and the reserved set share one list), 3 new and 1 reworded in the recognisers' doorbell battery (well-formed domain:X#N reads as before with its key; the short form refused in a key field and on To:; a reserved name refused in both places).

Why

PR #27881 (card #27637) keyed the mailbox by seat and read the To: line with seatKey, but left the key fields on SEAT_REF, which accepted skills#2. One message could then name a seat To: refused — two grammars for one thing. The contract review of #27881 (record 6513700361, should-fixes 1 and 4) asked for one grammar and for the reserved-word refusal the mailbox-open.mjs header assumed but did not enforce; triage 6513886980 ruled both in, and ruled that a well-formed To: domain:X#N line behaves exactly as before.

Clause-②: no — the accepted set narrows (the short form and the reserved names are refused; nothing new is accepted). No gate, workflow or queue guard reads a mailbox, so nothing lands or fails differently. .claude/skills/pm-dispatch/references/project-forms.md 〈信箱 PR〉 is untouched: it spells LANE#N and To: <席位>, neither of which now reads wrong.

Verification

  • node scripts/pm/mailbox-open.mjs --self-test — 71 cases in 10 batteries pass (was 67).
  • node scripts/pm/record-recognisers.mjs --self-test — 329 cases pass (was 326).
  • Ablations, each run once and the tree restored: dropping the reserved refusal in seatKey fails the two reserved pins in mailbox-open and the reserved pin in the recognisers; letting readSeat fall back to the old loose shape fails the short-form pin and the reserved pin; dropping key from the reading fails the three key-carrying pins. Nothing else moves.
  • Gate families derived by node scripts/pm/dispatch-gates.mjs --commands (2 paths vs merge base 9cd54fa): 31 families (check-closing-keyword-parity, check-declaration-mirrors, check-self-test-wired, check-self-test-workflow-commands, check-whole-set-label-write, plan-test-core-shards --self-test, bare-root-worklist --self-test, check:pm-record-recognisers, check:pm-dispatch-gates, check:scripts-symbol-anchors, check:entry-guard, check:parse-guard and the rest of the derived list) all exit 0 after pnpm install --frozen-lockfile --ignore-scripts; --ran with the recorded codes: 31 accounted for, 31 run, 0 NOT-MEASURED. eslint on the two files exit 0. git merge-tree against origin/main 4a5396b clean; no commit on main since the base touches either file.

Clause-②: no
Metadata-protocol: none

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (not touched)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes on the two files.
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. (nothing publishes: scripts/pm/** only, skip-changeset)
  • 6. packages/spec touched: its generated artifacts are regenerated and committed. (not touched)
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English.
  • The Before Submitting list in CONTRIBUTING.md is done.

维护者速读

  • 改了什么:信箱门铃七键里的 LANE#N 字段改用 seatKey 读,短写 skills#2 一律拒收;seatKey 另拒收撞保留车道词的 domain: 名(domain:triage、domain:repo-…)。
  • 为什么改:feat(pm): one mailbox per seat, not per account — the opener, the roster and the doorbell reader key it by seat #27881 之后 To: 行与键字段各用一套席位语法,一条消息可能一边读通一边拒收;分诊 6513886980 裁定统一到一套。
  • 风险与回滚:只收窄接受集;无门禁、workflow 或队列守卫读信箱,落地行为不变。回滚即 revert 本 PR。
  • 先看:scripts/pm/record-recognisers.mjs 的 readSeat,与 scripts/pm/mailbox-open.mjs 的 seatKey。
  • 两分钟验证:node scripts/pm/mailbox-open.mjs --self-test && node scripts/pm/record-recognisers.mjs --self-test。
  • 需要你做的:无。契约复审欠席位(contract review owed);落地档以登记簿为准(check-governed-merges.mjs --pr)。

🤖 Generated with Claude Code

https://claude.ai/code/session_016WV4d1a5iE1F79QjJupxQe

…h refuses reserved domain lane names

The seven doorbell keys' `LANE#N` fields were read with a second, looser
seat shape (`SEAT_REF`) that accepted the short form `skills#2`, while the
`To:` line above them read with `seatKey`. One seat grammar now: `readSeat`
calls `seatKey`, so the short form is refused in a key field exactly as on
`To:`, an absent number is seat 1, and the reading carries the canonical
`key`.

`seatKey` refuses a `domain:` lane named after a reserved lane word
(`domain:triage`, `domain:director`, `domain:repo-…`), whose slug would be
another seat's; the header had assumed that one-to-one promise. The lane
words are lifted into `SEAT_LANE_KINDS` and `SEAT_BARE_LANES`, the one
spelling the shape and the reserved set are both built from.

Pinned in the mailbox-open and record-recognisers self-tests: the short
form refused, a reserved name refused, a name that merely contains a
reserved word still read, and a well-formed `domain:X#N` line read as
before.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WV4d1a5iE1F79QjJupxQe
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 30, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-elon-musk · session_016WV4d1QkPVVzNz3FJqb2iS

Contract-review-claim: session_016WV4d1QkPVVzNz3FJqb2iS · head f37db59 · 2026-10-30T06:28Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-elon-musk · session_016WV4d1QkPVVzNz3FJqb2iS

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: f37db5978bb26456987badceec3ef7c5a7aca9c2
Local-runs: probe — on a detached worktree of this head: node scripts/pm/mailbox-open.mjs --self-test (71 cases, 10 batteries), node scripts/pm/record-recognisers.mjs --self-test (329 cases) and node scripts/pm/fleet-roster.mjs --self-test (82 cases), every one exit 0; the three ablations re-run by hand (below, ①.8); a base-vs-head differential of readMailboxLine and seatKey on 23 lines, run on a second worktree at the merge base 9cd54faae and on this head (①.1–①.6); after pnpm install --frozen-lockfile --ignore-scripts, eslint on the two files exit 0 and all 31 families dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derives for the two paths exit 0 (13 direct node, 18 pnpm; among them check:pm-record-recognisers = recognisers 329 + check-owed-reviews 63, check:pm-dispatch-gates 1937 fast-tier, check:entry-guard, check:parse-guard, check:scripts-symbol-anchors, check-self-test-wired, comment-mask corpus 19168 files 0 disagree), the same 31 the dev report counts. The opener's self-test is wired to no CI job (.github/workflows/lint.yml names only check:pm-record-recognisers), so its 4 new pins could be confirmed no other way. Nothing pushed, nothing written to GitHub, no mailbox opened or closed; both worktrees removed.
Scope: scripts/pm/record-recognisers.mjs (readSeat :1281, the three field readers :1333-1355, readMailboxLine :1378, the doorbell battery :2577-2624), scripts/pm/mailbox-open.mjs (SEAT_LANE_KINDS / SEAT_BARE_LANES / SEAT_SHAPE / RESERVED_DOMAIN_LANE :166-173, seatKey :186, the seat battery :531-541) + scripts/pm/fleet-roster.mjs (seatKey importer :103, seatSlugOf :245, parseSeat :184-195, read for callers), .claude/skills/pm-dispatch/references/project-forms.md 〈信箱 PR〉 :34-49 and the whole of .claude/skills for a short seat spelling (read, untouched), .claude/skills/pm-dispatch/SKILL.md lane table (the four lane kinds), .github/workflows/lint.yml :1262-1274 (which CI step runs the recogniser self-test), scripts/pm/check-governed-merges.mjs register (the tier), and the live mailboxes #27523, #27357, #27309, #27296, #25654 read for every LANE#N field and To: line on GitHub.

Card #27891, triage 6513886980 (p2 · domain:skills · area:devpath), claim 6516080492, Contract-review-claim 6516513547 on this head. One commit f37db597 on claude/project-thread-sji7vf; diff against the merge base 9cd54faae: two files, +40 −12. check-governed-merges --pr 27986 says NOT governed (no register path), so this record is the seat's own gate before the ordinary queue, as the dispatch order set it; the served tier is the order's, not the register's.

① Derived judgments

Each read off the committed tree and, where behaviour is claimed, off the base-vs-head differential (23 lines through readMailboxLine, 6 To: values through seatKey).

  1. A well-formed To: domain:X#N reads exactly as before: TRUE. readMailboxLine's To: path is byte-identical except that seatKey now returns null for a reserved domain: name (item 5); for domain:skills#2, triage, domain:my_lane, skills#2 the to reading and the refusal are the same on base and head. On the key fields, domain:skills#2, domain:ui#1, repo:cloud#1, triage#1, domain:my_lane#1 (an underscore, which both shapes accept) read on both trees with the same lane and n; the only addition is seat.key, the canonical spelling. The three readers (notify:seat-online, seat-offline, split) are the only callers of readSeat on this head; nothing outside record-recognisers.mjs imports readMailboxLine or mailboxEvents (grep over scripts/, .github/, package.json; the one CI mention is the self-test step), and no code reads seat.n or seat.lane outside the self-test. So no gate, patrol or workflow changes an exit — the file's own ⛔ line (:1239) still holds.
  2. The short form is refused everywhere: TRUE. skills#2 and a bare server in a key field move from read (base: { lane: 'skills', n: 2 }) to unreadable with reason does not spell …, matching the To: line's existing refused (names no seat). SEAT_REF is gone from the tree (grep: no definition, no reader). The ruling's one-grammar line is met: both envelope and key fields go through seatKey and no second shape remains.
  3. Bare triage reads n = 1, not null — RIGHT, and a pure canonicalisation. Downstream: no consumer of seat.n exists outside the battery (item 1), so nothing branched on null. The forms text names seats LANE#N and the roster's parseSeat already reads an absent number as 1 (fleet-roster.mjs:191, ?? 1), as does seatKey for To: (triage → triage#1, pinned since feat(pm): one mailbox per seat, not per account — the opener, the roster and the doorbell reader key it by seat #27881). A null here was the one place in the fleet where seat 1 was spelled as no seat. Existing records on GitHub: every LANE#N field on the five pm:mailbox PRs (open pm:mailbox — marchtian #27523, pm:mailbox — os-sales #27357, pm:mailbox — os-justin #27309; closed pm:mailbox — sunhaolin #27296, pm:mailbox — os-sales #25654) is a full domain:X#N (domain:skills#2, domain:ui#1..4, domain:server#1); none is bare or short-form, so no live record read differently. The self-test fixture that pinned null (a seat with no number reads (triage)) is rewritten by the diff to pin n === 1 && key === 'triage#1', and no other fixture depended on null. Accepted as part of the ruling, not a deviation.
  4. The accepted set is NOT purely narrowed — one widening, correct but mis-stated. The PR body and 维护者速读 say "nothing new is accepted". On the key fields, a lane name with a dot was UNREADABLE on base (SEAT_REF had no . in its class) and READS on head via seatKey ([a-z0-9._-]): repo:www.objectos.ai#2 (a real board seat, fixture fleet-roster.mjs:607) and domain:a.b#1. This is the one-grammar outcome the ruling asked for (the To: line already accepted it) and harms nothing, but the body's claim is wrong on this point. Also, a mixed-case key field (Domain:Skills#2) read with lane: 'Domain:Skills' on base and reads domain:skills on head — lower-casing as To: already did. Clause-②: no is still right: scripts/pm/** publishes nothing. Should-fix 1.
  5. Reserved domain: names refused: TRUE and complete. RESERVED_DOMAIN_LANE is ^(?:(?:triage|director)$|(?:repo)-), built from the same two lists as SEAT_SHAPE, applied only to the name after domain:. Completeness against the slug map (domain:X#N → X-N; repo:Y#N → repo-Y-N; triage#N → triage-N; director#N → director-N, with the name class excluding : and # and N a digit run): within one kind the slug is injective; the only cross-kind collisions are domain:triage ↔ triage, domain:director ↔ director and domain:repo-Y ↔ repo:Y, which is exactly the refused set. Differential: domain:triage on To: moved from read (key domain:triage#1, slug triage-1 — the triage seat's) to refused; domain:repo-cloud likewise (slug repo-cloud-1); in a key field both move to unreadable. domain:triage-tools#1, domain:directory, domain:repository still read (the pins at mailbox-open.mjs:538). Also narrowed, as intended by the four-kind shape: epic:x#1 read on base and is refused on head — epic: is a label kind, never a seat lane.
  6. One spelling of the lane words, no re-spelled duplicate: TRUE. SEAT_LANE_KINDS and SEAT_BARE_LANES are exported from mailbox-open.mjs; SEAT_SHAPE and RESERVED_DOMAIN_LANE are both built from them, pinned by mailbox-open.mjs:539. Elsewhere on the head the lane kinds are spelled only in prose: fleet-roster.mjs:26-28 (header) and parseSeat reads the lane as the seat post's first kind:name token with no word list; the pm-dispatch SKILL.md lane table; MAILBOX_KEYS' from/to prose. No code duplicate exists, so there was nothing to import (the dispatch order's "import rather than re-spell" is met by construction). The two exports have no importer yet — see should-fix 2.
  7. record-recognisers.mjs ↔ mailbox-open.mjs graph: the edge already existed on main (feat(pm): one mailbox per seat, not per account — the opener, the roster and the doorbell reader key it by seat #27881); this diff adds no import. No cycle.
  8. Self-tests and ablations, reproduced: mailbox-open 71 cases (was 67; the 4 new ones are the short-form, reserved-name, contains-a-word and one-list pins at :536-539), record-recognisers 329 (was 326; 3 new at :2614-2616, one reworded at :2613). Ablations, each run once by me and the tree restored by git checkout: (a) drop the reserved refusal line in seatKey → mailbox-open 2 failures (:537, :539), recognisers 1 of 329 (:2616); (b) readSeat falls back to the old loose shape when seatKey is null → recognisers 2 of 329 (:2615, :2616), mailbox-open green; (c) readSeat drops key → recognisers 3 of 329 (:2613, :2614, :2616). Exactly the three failure sets the dev report claims. The recognisers' reserved pin runs in CI (Lint · scoped · tooling self-tests → check:pm-record-recognisers), so the refusal is CI-covered transitively even though the opener's own battery is not.
  9. project-forms.md 〈信箱 PR〉 reads right untouched: its three doorbell lines spell LANE#N and the envelope To: 席位, never a short form; the self-test that every key template is verbatim in the text still passes (329 green). A grep of all of .claude/skills and AGENTS.md for a short seat spelling (skills#2-like, not preceded by domain:/repo:) finds nothing. No rule text now reads wrong; check:pm-skill-id-lint is not triggered (no .claude/** edit).
  10. Scope and declarations: the diff is exactly the two files the claim lists; PR body carries Fixes #27891, Clause-②: no, Metadata-protocol: none, the six 速读 lines, and says the review is owed and the tier is the register's. Label skip-changeset, Check Changeset green. The PR cites a dispatch-gates --commands run from the merge base; main is 8 commits ahead and ci.yml/lint.yml moved in that range (the tool warns STALE TREE on this head), but none of those 8 commits touches the two files, fleet-roster.mjs or project-forms.md; git merge-tree origin/main HEAD is clean.

② Semver level

No package publishes from scripts/pm/**; Clause-②: no, skip-changeset, no changeset, Check Changeset green. Consistent; no level to declare. (The accepted-set widening in ①.4 is on an internal PM reader, not a published surface.)

③ Boundary flags

  • Author: PR user.login is objectstack-fleet[bot]; attribution comment names os-elon-musk. No non-bot login to record.
  • Dev report deviations, each answered: (1) assignee/reviewer not set — consistent with the no-MCP-write posture, accepted; (2) bare triage n = 1 not null — ruled right in ①.3; (3) skip-changeset rode on pr_create — the gates derive no changeset for scripts/pm/**, accepted. open_questions: none. out_of_scope_findings: none.
  • Model: the order said default (opus); the report says fable, by the project rule for cards that may touch .claude/**. The card did not touch .claude/** in the end; no effect on the review.
  • The PR body's "nothing new is accepted" is over-stated (①.4); the landing ACCEPT should name the dotted-lane widening so the record is exact. Not a must-fix: the widening is the ruling's one grammar, and the file is governed by no register row.
  • Dispatch-gates derivation on this head reads a tree 8 commits behind main with ci.yml and lint.yml changed since; the PR's CI ran the merge with main, which is the reading that counts (②-gate below).
  • The opener's self-test is still wired to no CI job (as record 6513700361 noted); run here as the Local-runs probe. Should-fix 3.
  • Contract-review-claim 6516513547 names this session and this head; the only comment on the PR; no competing claim, no hold.
  • CI on f37db597 (REST commits/SHA/check-runs, final poll at the end of this review): 46 check runs, 26 success, 20 skipped by path filter, 0 in progress, 0 failures. Green: Governed Surface Queue Guard, PR-body guards, Check Changeset, Check PR Size, Lint · ESLint, Lint · PM dispatch-gates, Lint · repo & tooling gates, Lint · docs & code guards, Lint · CI/release/engine gates, Lint · scoped · tooling self-tests / query-options erasure / slot lookup & corpus, Lint & Repo Gates, Type Check × 5, Test Core (1/8) and (2/8), Test UI, Dogfood Regression Gate, Plan Test Core shards, Auto Label, filter. Condition ② of the landing check is met on this head.
  • Draft PR, mergeable_state: blocked, auto-merge not armed. Not governed, so after this PASS the seat lands it through the ordinary queue.

④ Design judgment

Rules-text face: none in hits (project-forms.md untouched and verified to read right in ①.9). The tooling that enforces the forms text is the whole diff, judged against the card's three Wanted items and the triage ruling:

  • record-recognisers.mjs readSeat — one grammar, by delegation to seatKey and deriving lane/n from the canonical key rather than keeping a parallel regex: the right shape, since a second regex is what the card was filed against. The reading gains key so a consumer can compare seats without re-joining the halves. The doorbell battery pins the well-formed line, the short form in all three key kinds and on To:, the reserved names in both places, and the contains-a-word case; each pin is load-bearing (①.8). Holds.
  • mailbox-open.mjs seatKey — the reserved set is derived from the slug map's actual collisions and from the same lists as the shape, not hand-listed, so adding a lane kind or bare lane later moves both together; the test at :539 pins that property. The header's one-to-one claim is now enforced where the slug is made, which is what should-fix 4 of 6513700361 asked. Holds.
  • Scenario check: a message To: domain:triage that would have landed in the triage seat's branch namespace is now refused at the envelope; Notify: split · skills#2 · … that read while To: skills#2 was refused is now refused too, with the same does not spell reason the template already carries. Both match the triage ruling verbatim.

No schema or ADR in hits; no first-consumer or execution-plan judgment is owed.

Implemented-by: claude/project-thread-sji7vf
Reviewed-by: session_016WV4d1QkPVVzNz3FJqb2iS

VERDICT: PASS

Must-fix: none.

Should-fix:

  1. PR body / 速读 and the landing ACCEPT: the claim "nothing new is accepted" is not exact. On the key fields a dotted lane name (repo:www.objectos.ai#2, a real seat; domain:a.b#1) was unreadable on main and reads now, and a mixed-case field is now lower-cased in seat.lane. Both are the one-grammar outcome and correct; name them in the ACCEPT so the review record and the body agree. No code change.
  2. SEAT_LANE_KINDS / SEAT_BARE_LANES are exported with no importer; fleet-roster.mjs parseSeat reads a seat post's lane as its first token with no word list, so a fifth lane kind on a seat post would be read by the roster and refused by the mailbox. A follow-up could have the roster's self-test assert every fixture lane's kind is in the exported lists (or parseSeat reject a kind outside them), making the lists the one spelling in fact and not only in mailbox-open.mjs.
  3. mailbox-open.mjs --self-test (now 71 cases, 4 of them this card's) is still run by no CI job; only the recognisers' reserved pin covers the refusal in CI. Wiring the opener's self-test into Lint · scoped · tooling self-tests is a one-line follow-up (check-self-test-wired is green only because the opener is not on CI's script list).

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · os-elon-musk · session_016WV4d1QkPVVzNz3FJqb2iS

维护者速读

  • 改了什么:信箱读者只剩一种席位写法。record-recognisers.mjs 里门铃键字段的席位改由 seatKey 解析,删掉 SEAT_REF,于是 skills#2 这类简写在键字段里和在 To: 行里一样被拒。mailbox-open.mjs 的 seatKey 拒收与保留车道词同名的 domain: 名(domain:triage / director / repo-…),车道词表导出为 SEAT_LANE_KINDS / SEAT_BARE_LANES。2 个文件,+40/−12。
  • 为什么改:PR feat(pm): one mailbox per seat, not per account — the opener, the roster and the doorbell reader key it by seat #27881 之后,同一条消息可以用两种拼法写收件席,但只有一种能被读到:To: skills#2 被拒,Notify: split · skills#2 · … 却能读。
  • 风险与回滚:不加门禁。写法规范的 To: domain:X#N 读法不变。行为上有三处变化,都是统一写法的应有结果:①键字段里带点的车道名(如名册夹具里的真实席位 repo:www.objectos.ai#2)以前读不出,现在能读;②大小写混写的键字段,seat.lane 现在统一为小写;③单写 triage 读作第 1 席,不再是空。线上 5 个 pm:mailbox PR 都用全称,没有记录依赖旧读法。revert 即回滚。
  • 先看:record-recognisers.mjs 的 readSeat,再看 mailbox-open.mjs 的 seatKey。
  • 两分钟验证:node scripts/pm/record-recognisers.mjs --self-test(329)与 node scripts/pm/mailbox-open.mjs --self-test(71)均 exit 0。
  • 需要你做的:无。登记册判定本 PR 不在受管面,契约复核 PASS(记录在本评论之前,Head-sha: f37db5978bb26456987badceec3ef7c5a7aca9c2),由本席转 ready 并开自动合并。

席位意见:ACCEPT。契约复核 PASS,没有 must-fix。should-fix 1(PR 正文说「不接受新写法」不够准确)已在本评论的风险一行写明,不改代码。should-fix 2、3(mailbox-open 自测没接进 CI,导出的车道词表没人引用)转到跟进卡 #27997。CI 全绿。

席位核对

  • 形态: one PR, Fixes #27891, two files: scripts/pm/record-recognisers.mjs, scripts/pm/mailbox-open.mjs; skip-changeset. check-governed-merges.mjs --pr 27986: NOT governed; ordinary queue landing.
  • 前提实测: readSeat has exactly three callers (the seat-online, seat-offline and split readers). seatKey is imported only by fleet-roster (seatSlugOf) and the recognisers. Nothing outside the recognisers reads seat.n / seat.lane. The reserved set is exactly the cross-kind slug collisions (domain:triage↔triage, domain:director↔director, domain:repo-Y↔repo:Y), built from the same lists as SEAT_SHAPE (review ①).
  • 门禁 check-runs: head f37db5978bb26456987badceec3ef7c5a7aca9c2: 46 check-runs, 26 success, 20 skipped, 0 failed, 0 pending. Locally 31 derived families exit 0. Three ablations each fail the intended pins.
  • 接受的偏差: none. project-forms.md 〈信箱 PR〉 spells LANE#N / To: 席位 and reads right, so it is untouched.
  • 范围外去向: pm(mailbox): wire mailbox-open --self-test into CI and pin the roster fixture lanes against SEAT_LANE_KINDS / SEAT_BARE_LANES #27997 (pm:blocked on this PR): wire mailbox-open.mjs --self-test into an existing CI script, and pin the roster fixture lanes against the exported lists.
  • 落地条款: not on the register, so the ordinary queue applies: the seat flips it ready and arms auto-merge on the contract review PASS, under the maintainer's landing grant for this term (seat thread, 2026-10-29 22:04Z).

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 30, 2026 07:03
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 30, 2026 07:03
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit f4826f8 Oct 30, 2026
47 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-sji7vf branch October 30, 2026 07:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

record-recognisers: the doorbell key fields still parse seats with SEAT_REF (accepts skills#2) while To: lines use seatKey; unify on one seat grammar

1 participant