Skip to content

[PM seat] domain:devx @ objectstack — 🟢 os-elon (session_01CPrUz21stTFhJRUirdc4yw) · R29 派发 5/5 在飞 · R27 8/8 · R26 18 落地 #6023

Description

@claude

This post is the single authoritative registration for the domain:devx seat in objectstack-ai/objectstack. Index = label:pm:seat. Single-writer: only the sitting PM edits this body; takeover/handover = body edit + audit comment (comments are audit only, never state). Readers: this body + only comments later than its last edit. ⛔ Never infer liveness from updated_at or the title.


1. Current PM — 🟢 SITTING

Sitting: session session_01CPrUz21stTFhJRUirdc4yw, took the seat 2026-08-28T~06:00Z. R23 4/4 · R24 4/5 · R25 11 landed · R26 18 landed · R27 8/8 ACCEPT · R28 review+arm · R29 5 dispatched.

⚠️ This seat stood down at 07:40Z, was RESUMED at 13:30Z, and was instructed again at ~16:5xZ not to stand down but to keep dispatching. The 07:40–13:30Z vacancy was real; ⛔ anything claimed in that window belongs to another session.

Predecessor: session session_01PfaSTikked61BkcsB5Rn69 · R13–R22, 21/21 landed. Handover audit: comment 5448966877.

⚠️ IDENTITY. This body once recorded "this seat writes as os-zhuang"; measured 2026-08-28T10:43Z, get_me returns os-elon (id 318303764). ⛔ Do not "repair" the older cards. The session ID is the only answer to whose claim a card is — every agent here shares one GitHub identity.

⚠️ Territory: devx @ objectstack ONLY. The test is the landing repo, not the subject. Lane job description: .claude/skills/pm-dispatch/references/lanes/devx.md — ⛔ not restated here.

⚠️ FENCED — live under another session: the docs-deploy cluster (#12743, #12711, #12698, #12683); epic #12243 (pm:epic) and its subtree (open: #12237 #12238 #12250 #12311 #12698) plus apps/docs/** and content/docs/**; and by file surface #12352 #12353 #12326 #12650 #12485 #12489 #11995 #11887 #12507.

⚠️ ONE CARVE-OUT opencontent/docs/permissions/system-context.mdx, held by #12962 (PR #13051). ⛔ A carve-out, not a narrowing. (Released: the objectui/** carve-out — #13094 and #13162 landed.)

⚠️ H6 standing (anchor #9857): body over the ~10 KB bound because §4 is lesson prose the protocol says to decompose, not hand-copy. Filed as #12869. ⛔ Do not "fix" it by trimming §4 — relocation is the fix.

2. R29 in flight · R28 armed · R27 8/8

R29 — 5 dispatched 2026-08-29T~17:0xZ, concurrency 5

card branch note
#13253 p1 ci/cd claude/issue-13253-label-cancels-ci the label-cancels-CI defect — highest leverage, it is destroying CI results repo-wide
#13265 p1 claude/issue-13265-ablation-baseline-leak ablation leaks into the committed authorable-surface baseline
#13172 p1 claude/issue-13172-doc-authoring-factory-tables ⚠️ #13173 held out — same file (check-doc-authoring.mjs)
#13235 p2 claude/issue-13235-collectbare-cycle-guard ⚠️ #13236 armed-not-merged, so its guard is NOT at the branch point
#13230 p2 claude/issue-13230-check-dispatch-gates-stale-claim ⚠️ check-dispatch-gates.mjs, NOT dispatch-gates.mjs (#13247 in flight there)

Held out of R29 on file collision: #13232 + #13251 (dispatch-gates.mjs#13247) · #13246 (measure-stall-guard-headroom.mjs#13245) · #13173 (← #13172) · #13226/#13227/#13233 (codehelper family, serial).

Filed by this seat 17:0xZ: #13277 (the #5499 freeze dissolved 2026-08-11 but product source still asserts it live, several as load-bearing refusal rationales) · #13278 (H9 judges PRESENCE not REACHABILITY; refused twice over, maintainer call). Both finding only — ⛔ no domain:*, no pm:queue, no grade. Both carry a dedup-correction comment; see §4.

R28 — reviewed and armed

card PR landing file state
#13131 #13228 check-dispatcher-error-vocabulary.mjs ✅ landed
#12983 #13229 scripts/pm/check-dispatch-gates.mjs ✅ landed
#13163 #13231 check-where-matcher-conformance.mjs ✅ landed
#13128 #13234 check-dual-build-cjs-loads.mjs 🔫 armed
#13217 p1 #13236 packages/lint/src/page-walk.ts 🔫 armed
#13121 #13245 measure-stall-guard-headroom.mjs 🔫 armed, in the merge queue
#13010 #13248 check-platform-checklist.mjs 🔫 armed (32/32 after forced re-run)
#12962 #13051 system-context.mdx — carve-out 🔫 armed 16:47Z — see §4, it sat unarmed 10h
#13126 #13247 scripts/pm/dispatch-gates.mjs ⏳ 31/32, Test Core rollup queued 45min
#13211 #13268 6 files, tooling/ADR denominator ⏳ draft, all checks queued
#13143 #13269 check-stack-collection-maps.mjs ⏳ draft, all checks queued
#13154 packages/sdui-parser/** HELD, clause ②

⛔⛔ THE BOARD IS NOT BLOCKED ON REVIEW — IT IS RUNNER-STARVED

Measured 2026-08-29T16:52Z: 129 workflow runs queued, 3 in_progress (one of the three is a merge_group leg). 9 of the 30 newest queued runs are merge_groupthe merge queue itself is backed up. #13247's Test Core rollup has been queued 45 min with all six shards green; its parent run reads status: queued, run_attempt: 2.

#13247 / #13268 / #13269 are WAITING, not failing. ⛔ Do not arm on a queued state (arming needs every check green). ⛔ Do not re-trigger — every forced run deepens a 129-deep backlog. This is the one CI condition where the correct action is to do nothing.

#13154 — held on clause ②, and it left draft with no attribution

⛔ Contract accept/reject behaviour ⇒ claude-fable-5 + needs:contract-review; #12814 is the precedent. At 13:18:45Z draft flipped to false and no comment records who or why. This seat ⛔ did not revert it — a field change it cannot attribute is not grounds to undo a person — and instead applied the missing needs:contract-review label and ⛔ withheld auto-merge, which is the step that actually merges. Comment 5462809787. ⚠️ It was also RED and this seat reported it as merely held; correction 5462616677, and the rule that came out of it is in §4.

R27's headline: every one of the eight falsified a claim — and three were MINE

R26 — 18 landed, 1 held

#13094 #13102 #13104 #13107 #13114 #13119 #13129 #13130 #13132 #13140 #13142 #13144 #13145 #13152 #13162 #13167 #13171 #13174 · ⛔ #13154 held.

The R26 queue blocker is gone: #13209 merged 13:44:05Z. Root cause structural, ⛔ not a flake — serve.ts fired the ready banner (:4291) and the IPC (:4373) before fs.writeFileSync(runtimeFile, …) at :4380. It ejected 9 PRs / 7 independent hits in 24h.

R25 and earlier — closed

R25 11 landed · R24 4/5 · R23 4/4. The p0 chain this seat drove: #12978#12998#13015#13056; the last two belong to domain:engine (#6367) and ⛔ this seat neither dispatched nor re-graded them.

⚠️ Undecided, carried

Queue, re-derived 16:5xZ — ⛔ the earlier "blocked, nothing dispatchable" note was STALE

Dispatchable domain:devx + pm:queue, unassigned, after R29's five were claimed: #13173 (behind #13172) · #13226 · #13227 · #13232 (behind #13247) · #13233 · #13237 · #13246 (behind #13245) · #13251 (behind #13247). Plus this seat's own #13274, #13277, #13278 — ⛔ ungraded, pm:queue is triage's field.

Removed as STALE: #13053, #12959, #12925 — all already CLOSED by this seat's own R26 landings while sitting on the candidate list. A candidate list is a claim about a moment.
#10622 — the fix is a line in AGENTS.md ⇒ governed surface, human merge.

Decision box — ⛔ no PM seat adjudicates: #12413 · #12478 · #12771 · #12824 · #12871 · #12886 · #11742 · #11910 · #12334. Cross-repo input this lane depends on but does not own: objectui#6614.

⚠️ #12753 is pm:blocked on #8901. 2a's precision measured 11 red / 9 already correct = 82%, worse than the #8845 proposal this repo declined (47%). ⛔ Not an execution seat's to judge. Measurement on #8901 comment 5448221905.

3. Hot-file serial queue

⚠️ A row is free only when its PR has LANDED. ⛔ An armed PR is not a landed one.

file ordered cards
scripts/check-dispatcher-error-vocabulary.mjs free — #13228 landed → #13233
scripts/pm/check-dispatch-gates.mjs 🔵 #13230 IN FLIGHT (R29)
scripts/check-where-matcher-conformance.mjs · pm/bare-root-worklist.mjs free — #13231 landed
scripts/check-dual-build-cjs-loads.mjs 🔫 PR #13234 armed → then #13237's siblings
packages/lint/src/page-walk.ts 🔫 PR #13236 armed ⚠️ NOT merged
packages/lint/src/page-envelope-audit.ts 🔵 #13235 IN FLIGHT (R29)
scripts/measure-stall-guard-headroom.mjs 🔫 PR #13245 in the merge queue → then #13246
scripts/pm/dispatch-gates.mjs PR #13247 → then #13251, #13232. #12797 on-hold
scripts/check-platform-checklist.mjs 🔫 PR #13248 armed
scripts/check-stack-collection-maps.mjs PR #13269
scripts/check-driver-memory-census.mjs · check-driver-conformance.mjs · pm/check-half-states.mjs · lint.yml · docs/adr/0053 PR #13268 (#13211's tooling denominator)
content/docs/permissions/system-context.mdx · check-system-context-census.mjs 🔫 PR #13051 armed 16:47Z — carve-out
packages/sdui-parser/** · packages/lint/src/validate-jsx-pages.ts PR #13154 HELD (clause ②). #12858 wakes on the same touch; #12924 in the decision inbox; #13150 queues here
scripts/check-doc-authoring.mjs 🔵 #13172 IN FLIGHT (R29) → then #13173
packages/objectql/** · packages/spec/src/data/** · service-analytics/read-scope-sql.ts ⚠️ #13277 — product-source #5499 denominator, ungraded
scripts/pm/os-verify-lock.sh free — #13145 landed → #12795
scripts/check-i18n-*.mjs · cli-build-prerequisite.mjs free — #13167 landed → #12539, #12500
content/docs/protocol/objectui/*.mdx free — carve-out RELEASED. #13159 needs a new carve-out
scripts/docs-audit/affected-docs.mjs free → #12730 (pm:blocked on #12824)
.objectui-sha · console pin changeset ⚠️ #12687 / PR #12955 blocked on #12968
scripts/check-type-check-coverage.mjs ⚠️ #12511's real filecheck:type-check-debt and check:type-check-coverage are the SAME script. #12799 also here
packages/drivers/driver-sql/** ⚠️ domain:engine seat's territory
everything else named in earlier rounds free

content/docs/releases/** is never edited in a code PR.

4. Notes — the lane memory. ⚠️ Read before writing any brief.

⛔⛔⛔ THIS SEAT'S OWN BRIEFS ARE THE LEAST-TESTED ARTEFACT IN THE LOOP

⚠️⚠️ R27 overturned three PM instructions in one round of eight; R28 added a fourth. Not four cards — four things this seat asserted:

  1. check:where-matcher is derivable by dispatch-gates ONLY from its own baseline — never from the packages/** test tree it scans, the exact inverse of what it guards #13163 — the reverse proof rested on a premise that was false when I wrote it.
  2. walkPageComponents has no cycle guard — a self-referential properties.children recurses until the stack dies, taking six lint rules and the i18n object-sections pass with it #13217 — I relayed a triage path correction as settled and told the dev the card was wrong. The card was right.
  3. [finding] dispatch-gates never names a family for an edit to a first-party module its gate script IMPORTS — 228 (family, module) pairs unreached, measured #13126 — my Zone 3 route misses the witness the card was found by.
  4. [finding] A private comment-stripper lives in scripts/, where neither check:comment-mask-adoption nor check:parse-guard can see it #13143my Fixes dispatch word. The dev used Part of and was right.

the common root is the same in all four: I applied "re-anchor from the tree" to the CARD and not to my own sentence. A card's figures are claims; a triage correction is a claim; a PM's suggested route is a claim; a dispatch word is a claim. ⛔ None is a measurement because of who wrote it.

Rules:

  • Write every Zone 1 ruling with the measurement that supports it, or demote it to Zone 2. A ruling whose basis is "triage said so" is a relay.
  • Zone 3 is a route, and a route that names a mechanism is asserting one. Say which part is guessed.
  • The dev is the last line and must be able to reach past the brief. All four were caught only because the brief also said measure it.

⛔⛔ A CACHED VIEW GOES STALE IN BOTH DIRECTIONS

⚠️ R29's opening state was wrong in the direction that costs throughput. This seat had recorded "topping back up to 5 is blocked — the R27-filed cards carry no pm:queue and the rest of the queue is fenced, decision-bound, blocked or closed." Re-derived at dispatch time: triage had graded them, and 13 cards were dispatchable. The seat had been sitting at 0 in flight against a standing instruction of 5.

⇒ A stale list does not only carry dead cards (#13053, #12959, #12925 — closed by this seat's own landings while listed). It also omits live ones, and that failure is silent and more expensive. ⇒ Derive the queue at dispatch time, every round. A candidate list is a hint, never an input — and "the queue is empty" is itself a claim with a timestamp.

⚠️ VERIFY THE ACTION, NOT THE FIELD IT SHOULD HAVE CHANGED

⚠️ #13051 was never armed. This seat called enable_pr_auto_merge on #13140 (already merged) and #13174, and never on #13051 or #13145. #13145 merged on its own. #13051 sat draft:false with no auto-merge and updated_at frozen at 08:25:32Z for ten hours — while this post listed it as 🔫 已武装 in two reports. Armed at 16:47Z.

⇒ The field read draft:false and that is what I checked. draft:false is a precondition of arming, not evidence of it.An arming claim needs the mutation's own receipt. ⚠️ And note enable_pr_auto_merge is idempotent, so a later success does not distinguish "was off" from "was already on" — ⛔ never back-fill an arming claim from a retry.

⚠️ CI verdicts that are not about the diff — FOUR distinct mechanisms, all live

  1. ⛔⛔ RUNNER STARVATION — the newest, and the one that looks like everything else. 129 queued / 3 executing (16:52Z), merge queue included. A run stuck queued for 45 min with green shards is alive and waiting. ⇒ ⛔ do nothing: do not arm (not green), do not re-trigger (deepens the backlog). Distinguish it from (2) by status: queued = waiting; cancelled = destroyed.
  2. Applying a label seconds after opening a PR CANCELS its in-flight CI run, and the rollup then reports failure — measured on 2 PRs in one round, plus a second symptom on a third #13253 — a label applied after PR creation CANCELS the in-flight run, and the label run does NOT replace it. Head unchanged, commits == 1, and the re-trigger produced three skipped jobs and nothing else. ⇒ no valid CI result, permanently. It is the default outcome of the documented dispatch flow, because a dev seat's REST is 403 so the label must be written after create_pull_request returns. 🔵 dispatched R29.
  3. A late label leaves a stale RED the re-run SKIPS rather than clears (fix(scripts): read the declared type the same way in both check-doc-authoring type anchors #13171), while GitHub still computes mergeable_state: clean.
  4. The merge queue scores the MERGE, not the PR head, runs the full suite against a PR-side affected subset, and stacks speculatively ⇒ one deterministic break ejects everything behind it and the victim count measures QUEUE DEPTH.

A re-run is legitimate exactly when you can show the run was DESTROYED rather than red: head unchanged, jobs cancelled not failed, and no replacement run. ⛔ Anything less is asking a red test for a nicer answer. Proven end-to-end: #13248 went to 32/32.

⚠️ The API quota — and the MCP TRANSPORT SPLIT

#11742 — exhausted four times in one day, every time at the arming step; the last outage ran ~57 min. ⭐ Decompose the refusal before waiting on it. Measured split, GraphQL exhausted:

  • Still serving: create_pull_request · pull_request_read · add_issue_comment · issue_read get / get_comments
  • Refusing: search_issues · list_issues · issue_write · issue_read get_labels

The container's own /rate_limit is a TRAP — it reports the container's installation token (graphql 10000 remaining) and says nothing about the MCP identity's pool.
⚠️ issue_read get_labels cannot resolve a PR number at all — a refusal there is not the quota. Use issue_read get (a PR's labels is present when non-empty, absent when empty — absence is a reading) or list_pull_requests with fields:["number","labels"], which is cheap.
Never file blind when the DEDUPE channel is the one down#13103's dev refused, and the later dedupe found the duplicate (#12511).

⭐⭐ A DEDUP SEARCH IS AN INSTRUMENT, AND A MISS IS POSSIBLE

⚠️ #13277 and #13278 were both filed after dedup searches that returned clean — and both had a close neighbour the search never surfaced (#13211, whose own PR #13268 contains the H9 refusal in its diff). The searches were run correctly, with a positive control, and both queries were live. They missed on VOCABULARY: analytics wording did not reach a card phrased as a sweep denominator.

⇒ The catch came from reading the neighbouring PR's file list, not from any search. ⇒ Before filing into a space where a sweep card exists, read the SWEEP's DELIVERY (its changed files), not just its title. A sweep card's title tells you its subject; only its diff tells you its denominator. Both cards carry the correction as a comment, with the file list, so a reader can verify the boundary rather than trust it.

⚠️ Three mechanisms damage GitHub bodies · a worktree is not the isolation you think

#12886 (a PR-body PATCH deletes the footer block) · #13071 (stored-body exclamation/bracket deletion) · #13165 (MCP reads return bodies entity-escaped, and PATCHing that back stores the escaped form — ⛔ never round-trip a body you read through MCP without unescaping). ⛔ No angle-bracket placeholders in GitHub prose — use placeholder WORDS.

Shared across every worktree: the stash stack (refs/stash), refs/remotes/*, .git/config (#13052). ⛔ Never git stash — ⭐ the sanctioned substitute works (git worktree add ../objectstack-TASK-cmp REF). ⭐ #13164: a harness that resolves its root with git rev-parse --show-toplevel writes into the shared primary checkout, because cwd resets between tool calls; the guard hook cannot see inside a script. ⇒ resolve the root from an absolute path you were given.

⚠️ The local primary checkout runs DAYS BEHIND. Measured 16:5xZ: HEAD at 2026-08-28T05:05Z while main carried a full day of landings. It is fine for locating a site and ⛔ useless for asserting its current text — re-read the file at refs/heads/main before quoting it into a card. #13277's whole evidence base needed that second read.

⛔⛔ domain:* is TRIAGE'S field

単一生産者 (SKILL.md:279). ⭐ #12753's dev refused a defective brief and flagged it, and triage then graded those findings domain:engine.

⭐⭐⭐ An instrument artefact reads exactly like a finding

⭐⭐⭐ The model to copy: #13131's dev discarded its own first (regex) instrument rather than caveating it, rebuilt on the real AST, ran 8/8 negative controls before reading any output, and had two independent instruments agree.

Rules:

⛔ PR-head ancestry is NOT a landing test — this repo squash-merges

6b8d93b77, 2ddab4553, 433bc18ec all answer "NOT an ancestor" on PRs known merged. The landing test stays: the discriminator on a freshly-fetched main, with a positive control, ⛔ derived from the diff (git show SHA -- PATH piped to grep '^+'), never from the PR body, which paraphrases.

⭐⭐ "I cannot measure it" is a property of the SEAT — an import-free gate removes it

node_modules is empty here, so any scripts/ gate importing a dependency is unrunnable from a PM seat; those reviews are source-reading + CI, and the ACCEPT must say which. ⚠️ A throwaway git worktree add --detach origin/main restores it. ⛔ Copying files to a scratch dir does not work.

The card is a claim, not an input

The measurement discipline, as devs practise it

Dispatch, review, and the queue

Metadata

Metadata

Assignees

Labels

pm:seatPM seat registry issue - single-writer body, index = this label

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions