You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Seat registration post for the domain:ui lane (objectui execution seat), created under the maintainer's 2026-08-21 ruling that split objectui cards three ways (domain:devx / domain:spec / domain:ui, the last being the only new label).
Body is authoritative; title and assignee are derived views. Single writer: the sitting seat PM. Comments are audit only and never carry state.
1. Current PM
Session: session_019ZyKZejBWZoCSj1NP35wcp (took over 2026-08-24 ~04:00Z, at the maintainer's explicit direction: 「你接手」)
Posture: R34 opening ~04:00Z. Predecessor session_01EuPCi56cnGyykygi3z9w4m last wrote this body 2026-08-23T17:57Z and went dark; a further session (68ad4d1a-c111-591c-9633-f2fb64fa1803) worked the lane 19:00Z–02:51Z without ever writing here. See §2.
Default tier is Opus — maintainer, 2026-08-23: 「Fable 5 配额已耗尽,可以用 Opus 继续,并发还是保持 5」. A model-quota exhaustion is a tier fact, never a density fact. ⛔ Do not reduce density on resource grounds; R30 tried and was overridden.
Dispatch autonomously — maintainer, 2026-08-22: 「你应该自主派发,并发保持3」. No per-round confirmation; only genuine manual-floor items go up.
This seat may dispatch above its own served tier — maintainer, 2026-08-22: 「你虽然是 opus,但是可以派 fable 的卡」.
Clause-② at-tier dispatch is the route in this repo — maintainer, 2026-08-22: 「直接入队」. ⚠️needs:contract-reviewdoes not exist as a label in this repo (ensure-pm-labels.sh creates it for objectstack only), so the compensating-label route is unavailable here by construction.
2. Inherited ledger — TWO predecessors, one of which left no record
⛔ The seat post is not a reliable account of this lane's last twelve hours, and a successor must not read it as one. Two distinct handover failures stack here:
⚠️The mutex protocol did not catch this, and the reason is worth carrying. The three prescribed readings (last shift briefing / newest open-round marker / newest non-self Claim: on a pm:dispatched card) all read clear while a session was actively landing PRs. The third reading is blind whenever a session does not use the pm:dispatched label — and 68ad4d1a did not: its cards went pm:queue → closed. A stale seat post plus an unused status label is indistinguishable from a free seat. The reading that actually settled it was the claim comment on the most recently closed card (#4919, 02:09:40Z, naming a third session id). ✅ Add that to the mutex read: the newest closed card in the lane, not only the pm:dispatched ones.
3. Hot-file serial queue
No fences held at takeover.git ls-remote --heads origin 'refs/heads/claude/*' shows zeroclaude/issue-* branches for any open card in this lane, and the only open claude/issue-* PR in the repo (#5948, claude/issue-4477-playwright-configs-in-tsconfig) belongs to another lane. Nothing was in flight at takeover.
Half-states repaired at takeover — five cards left pm:queue + assigned with their PR already merged. All five had landed work and no remote branch, so each was invisible to candidate queries (which need pm:queueand no assignee) and equally invisible to stale-claim reclaim (which keys off a live claim):
⛔ not dispatchable — anchor for the maintainer's Option-C ruling; the enforcement lands upstream at objectstack#11437 / PR #11560. Moved to pm:blocked + Blocked-by:.
burn-down card — correctly stays open, a PR closes a slice not the card; assignee cleared so the next group is dispatchable.
4. Landing ledger
⛔ NOT CARRIED FORWARD FROM THE PREDECESSOR'S FIGURE. The inherited body claims "Rounds 1–32: 138 cards resolved, 134 PRs merged" as of 17:42Z. That figure cannot be extended across the gap, because the intervening session's ~14 closures are not this seat's in the sense the ledger counts, and the ledger's own documented blind spot 3 says the closed-issue query returns cards closed by any seat. Re-derive from per-round deltas going forward; ⛔ never increment.
The derivation method and its five recorded blind spots are unchanged and still authoritative:
⛔ Do not count from the merged-PR list (other lanes' PRs merge in the same window).
⛔ THE REST CHANNEL IS DEAD IN THIS SESSION — the predecessor's §5 instruction to use it CANNOT BE FOLLOWED, and following it blind wastes a round.GH_TOKEN is present in the environment, but a direct curl https://api.github.com/... returns 403 with {"message":"GitHub access is not enabled for this session. An org admin must connect the Claude GitHub App for this organization."}. The agent proxy, not GitHub, is the refusal point. Everything must go through the MCP tools in this session.
⚠️ That matters because the predecessor's fix for the next item depended on REST. MCP list_issues's labels parameter is an OR, not an AND — independently re-confirmed at takeover: a request for domain:ui ∩ pm:dispatched returned 135 items against the lane's own 132. A wider result than either input is the tell.
✅ The working method without REST: request one label (domain:ui), take fields including labels and assignees, paginate with the after cursor (132 open cards = 2 pages at perPage: 100), and intersect client-side. This is exactly the "整车道一次读全,本地求交" the protocol prescribes, and it costs two calls.
⚠️search_issues with a label: query returned total_count: 0 for a query whose answer is non-empty. ⛔ Do not use it for lane scans.
⛔ READ EACH PR'S GATES BY NAME, ONCE, ~11 MINUTES AFTER THAT PR'S OWN RUN started_at — not the PR's creation, not another PR's clock. Measured shard window 8m54s–10m36s. An early read is a discipline failure, not a judgement failure; the fix is a wall-clock check before the request.
⛔ check_suite.completed: success is not a gate reading. ⛔ mergeable_state: unknown is notclean — it is still computing (resolves ~20 s later).
The universal judge: every workflow run on the head completed, no check failure/cancelled, and mergeable_state: clean. The green count is 22 for a code PR but legitimately 20 for a docs-only diff (Changeset Bump Policy and Live E2E never fire). Keep 22 as the guard against reading a still-being-created listing as green, ⛔ not as a universal constant.
⛔ 入队资格 = every check green, NOT the required subset. A PR with required-green but a red test shard was queued once and turned main red for about an hour.
⛔ Build Docs GREEN IN ~10 SECONDS IS A PATH-FILTERED SKIP, NOT A BUILD — the job gates its steps on git diff -- 'apps/site/' 'content/'. ⚠️ But duration is not the discriminator; the executed step is: a warm Turbo cache made a real content/-touching build finish in 47 s. ⛔ Do not reject a fast Build Docs on the clock alone — read whether Build Site ran. On push/merge_group the job always builds, so main's own push run is the honest reading.
⛔ A MEASURED GRAPHQL BUDGET IS NOT A RESERVATION. Landing calls (update_pull_request to un-draft, enable_pr_auto_merge) run on GraphQL (5000/hr, shared across every seat); reads run on REST core. The bucket drained seven times on 2026-08-23. ⛔ Never retry a rate-limited call. ✅ Batch the landings, and read each gate immediately adjacent to its landing call — a clean reading decays to behind the moment main moves.
⛔ A CHANGESET IS NOT ALWAYS OWED — run node scripts/check-changeset-presence.mjs and follow it. A docs-only diff legitimately owes none; objectui has no skip-changeset label, and an empty-frontmatter changeset is this repo's declaration mechanism.
⚠️objectui does NOT have scripts/pm/.dispatch-gates.mjs lives in objectstack and derives against objectstack's workflows; pointed at objectui paths it prints a confident gate list (check:slot-lookup and five more) of gates that do not exist here. Its --tier line remains usable as a floor; its gate families are not. objectui's real gates come from its own 22 workflows and root package.json. Same for os-verify-lock.sh (container-global entry point in the sibling checkout is established practice) and half-state-patrol.yml (objectstack only).
⚠️Brief app-shell cards to run path-filtered. The whole-package packages/app-shell vitest suite takes ~784 s (506 files / 4923 tests) and holds the shared verify lock the entire time, starving every other dev on the machine.
⛔ A subagent's send_later fires into the PM's session, not its own. Brief devs not to schedule their own check-ins: reading the gate and landing are the PM's job, and the dev's report is the handoff.
✅ A claim comment from a different session id blocks, UNLESS it is demonstrably spent — report returned, round closed, card re-queued, and no branch on the remote. The burden is evidence, not assumption, and the evidence goes in the new claim comment so the next reader does not re-derive it.
✅ A GOVERNED-SURFACE CARD SPLITS INTO TWO PRs.docs/adr/**, .claude/**, skills/**, AGENTS.md, CLAUDE.md stop at draft for human merge. PR 1 = ordinary sites (lands normally, must carry Part of #N, ⛔ never a closing keyword, or the card auto-closes and orphans the governed half); PR 2 = the governed file alone, draft, ⛔ never flipped ready / enqueued / auto-merged. Request review from os-zhuang; ⚠️ when the PR author is os-zhuang, GitHub refuses with an author-identity 422 — assign instead and say so in the round report.
Seat registration post for the
domain:uilane (objectui execution seat), created under the maintainer's 2026-08-21 ruling that split objectui cards three ways (domain:devx/domain:spec/domain:ui, the last being the only new label).Body is authoritative; title and assignee are derived views. Single writer: the sitting seat PM. Comments are audit only and never carry state.
1. Current PM
session_019ZyKZejBWZoCSj1NP35wcp(took over 2026-08-24 ~04:00Z, at the maintainer's explicit direction: 「你接手」)domain:ui@objectstack-ai/objectui(execution seat)session_01EuPCi56cnGyykygi3z9w4mlast wrote this body 2026-08-23T17:57Z and went dark; a further session (68ad4d1a-c111-591c-9633-f2fb64fa1803) worked the lane 19:00Z–02:51Z without ever writing here. See §2.needs:contract-reviewdoes not exist as a label in this repo (ensure-pm-labels.shcreates it for objectstack only), so the compensating-label route is unavailable here by construction.2. Inherited ledger — TWO predecessors, one of which left no record
⛔ The seat post is not a reliable account of this lane's last twelve hours, and a successor must not read it as one. Two distinct handover failures stack here:
session_01EuPCi56cnGyykygi3z9w4mwrote this body at 17:57Z describing R33 as just dispatched ([finding] RecordDetailView hand-copies record:activity's sys_activity map, and nothing fails when the two disagree #5878 · record:activity widens on a badtypesfilter: an unrecognised or empty kind list renders EVERY activity, not none #5841 ·warnOnUnknownActionKeys's dev-console message states a fact step 3 retired, and points the author at the wrong file #5642 · [finding] A THIRD hand-written FormViewSchema mirror survives inpackages/react's spec bridge, and it has drifted on three keys #5596 just measured #5652 · [finding]PluginComponentInputis a published name with zero consumers, and after #4972 it is a pure alias ofComponentInput#5674) and then went dark. R33 in fact completed:warnOnUnknownActionKeys's dev-console message states a fact step 3 retired, and points the author at the wrong file #5642 closed 18:09Z; [finding] RecordDetailView hand-copies record:activity's sys_activity map, and nothing fails when the two disagree #5878, record:activity widens on a badtypesfilter: an unrecognised or empty kind list renders EVERY activity, not none #5841, [finding] A THIRD hand-written FormViewSchema mirror survives inpackages/react's spec bridge, and it has drifted on three keys #5596 just measured #5652 closed 18:43Z. [finding]PluginComponentInputis a published name with zero consumers, and after #4972 it is a pure alias ofComponentInput#5674 landed its PR refactor(types): deprecate PluginComponentInput in favour of ComponentInput (stage 1 of 2) #5897 and was left open with a stale assignee — see §3.68ad4d1a-c111-591c-9633-f2fb64fa1803then worked this lane from ~19:00Z to 02:51Z — at least fourteen cards closed in that window — and never wrote to this seat post at all. Its work is real and landed (five PRs merged in one queue trip at 02:50:2x–02:50:38Z: Gate authored icon names against lucide's runtimeiconsrecord #5932, feat(core,app-shell): read ActionSchema.onSuccess for post-success navigation #5933, test(types): extend the zod-mirror anti-drift guard from BaseSchema to the whole mirror population #5929, docs(blocks): correct block-schema.mdx to the declared vocabulary, drop the phantomslotnode #5937, feat(types,mobile)!: retire the MobileOverrides type and its mount point (#4919) #5941).Claim:on apm:dispatchedcard) all read clear while a session was actively landing PRs. The third reading is blind whenever a session does not use thepm:dispatchedlabel — and68ad4d1adid not: its cards wentpm:queue→ closed. A stale seat post plus an unused status label is indistinguishable from a free seat. The reading that actually settled it was the claim comment on the most recently closed card (#4919, 02:09:40Z, naming a third session id). ✅ Add that to the mutex read: the newest closed card in the lane, not only thepm:dispatchedones.3. Hot-file serial queue
No fences held at takeover.
git ls-remote --heads origin 'refs/heads/claude/*'shows zeroclaude/issue-*branches for any open card in this lane, and the only openclaude/issue-*PR in the repo (#5948,claude/issue-4477-playwright-configs-in-tsconfig) belongs to another lane. Nothing was in flight at takeover.Half-states repaired at takeover — five cards left
pm:queue+ assigned with their PR already merged. All five had landed work and no remote branch, so each was invisible to candidate queries (which needpm:queueand no assignee) and equally invisible to stale-claim reclaim (which keys off a live claim):Part of)pm:blocked+Blocked-by:.Part of, deliberate)pm:on-hold); assignee cleared.pm:on-hold); assignee cleared.4. Landing ledger
⛔ NOT CARRIED FORWARD FROM THE PREDECESSOR'S FIGURE. The inherited body claims "Rounds 1–32: 138 cards resolved, 134 PRs merged" as of 17:42Z. That figure cannot be extended across the gap, because the intervening session's ~14 closures are not this seat's in the sense the ledger counts, and the ledger's own documented blind spot 3 says the closed-issue query returns cards closed by any seat. Re-derive from per-round deltas going forward; ⛔ never increment.
The derivation method and its five recorded blind spots are unchanged and still authoritative:
domain:ui(Build Docsis red onmain:fsreaches the browser bundle via@objectstack/spec→pg-connection-string#5668 wasdomain:devx).closed_atin THIS round's window, never by the dispatch list.ADR-0057 D10citations to the framework'sADR-0124 D1— D10 decides Setup-nav capability surfacing, not enforcement location, and the framework's own ADR says so #5701 → docs(citations): re-anchor the eightADR-0057 D10citations to the framework'sADR-0124 D1(#5701) #5842 + docs(adr-0036): re-anchor the enforcement-rule citation to the framework'sADR-0124 D1(#5701) [GOVERNED SURFACE — human merge] #5843), so "PRs = cards − no-PR cards" is false.R34 onward is counted fresh from this takeover.
5. Notes
⛔ THE REST CHANNEL IS DEAD IN THIS SESSION — the predecessor's §5 instruction to use it CANNOT BE FOLLOWED, and following it blind wastes a round.
GH_TOKENis present in the environment, but a directcurl https://api.github.com/...returns 403 with{"message":"GitHub access is not enabled for this session. An org admin must connect the Claude GitHub App for this organization."}. The agent proxy, not GitHub, is the refusal point. Everything must go through the MCP tools in this session.list_issues'slabelsparameter is an OR, not an AND — independently re-confirmed at takeover: a request fordomain:ui∩pm:dispatchedreturned 135 items against the lane's own 132. A wider result than either input is the tell.domain:ui), takefieldsincludinglabelsandassignees, paginate with theaftercursor (132 open cards = 2 pages atperPage: 100), and intersect client-side. This is exactly the "整车道一次读全,本地求交" the protocol prescribes, and it costs two calls.search_issueswith alabel:query returnedtotal_count: 0for a query whose answer is non-empty. ⛔ Do not use it for lane scans.⛔ A FENCE BUILT ON A FILE PATH YOU DID NOT VERIFY IS NOT A FENCE — it fails in both directions, and the predecessor hit both in one day. False positive: [finding] ObjectView 是最后一处不走共享 sort sink 的读点 ——
$orderby: sort原样透传,归一化外包给了某一个 adapter #4869 held behind plugin-viewobject-view:showRefreshis a declared, documented, defaulted designer input that nothing reads #5567 on a sharedObjectView.tsxthat was two different files (plugin-view/vsapp-shell/src/views/) — a basename is not a path. False negative: [finding] Two plugin-detail spec-parity tests still narrate rc.6 strip-mode as fact — stale prose that survives the GA pin because no assertion depends on it #4918 serialised behind finding: 墓碑判据还剩两份本地副本(plugin-detail / app-shell),都只有结构通道,共享 judge 已就位 #4947 as "same package, different files" when they were the same file. ✅ Resolve every card's file surface to a full path before fencing it; the counter-example is cheap — three concurrentpackages/typescards were safe in R28 because each symbol was located first.⛔ READ EACH PR'S GATES BY NAME, ONCE, ~11 MINUTES AFTER THAT PR'S OWN RUN
started_at— not the PR's creation, not another PR's clock. Measured shard window 8m54s–10m36s. An early read is a discipline failure, not a judgement failure; the fix is a wall-clock check before the request.check_suite.completed: successis not a gate reading. ⛔mergeable_state: unknownis notclean— it is still computing (resolves ~20 s later).completed, no checkfailure/cancelled, andmergeable_state: clean. The green count is 22 for a code PR but legitimately 20 for a docs-only diff (Changeset Bump PolicyandLive E2Enever fire). Keep 22 as the guard against reading a still-being-created listing as green, ⛔ not as a universal constant.mainred for about an hour.⛔⚠️ But duration is not the discriminator; the executed step is: a warm Turbo cache made a real
Build DocsGREEN IN ~10 SECONDS IS A PATH-FILTERED SKIP, NOT A BUILD — the job gates its steps ongit diff -- 'apps/site/' 'content/'.content/-touching build finish in 47 s. ⛔ Do not reject a fastBuild Docson the clock alone — read whetherBuild Siteran. Onpush/merge_groupthe job always builds, so main's own push run is the honest reading.⛔ A MEASURED GRAPHQL BUDGET IS NOT A RESERVATION. Landing calls (
update_pull_requestto un-draft,enable_pr_auto_merge) run on GraphQL (5000/hr, shared across every seat); reads run on REST core. The bucket drained seven times on 2026-08-23. ⛔ Never retry a rate-limited call. ✅ Batch the landings, and read each gate immediately adjacent to its landing call — acleanreading decays tobehindthe momentmainmoves.⛔ A CHANGESET IS NOT ALWAYS OWED — run
node scripts/check-changeset-presence.mjsand follow it. A docs-only diff legitimately owes none; objectui has noskip-changesetlabel, and an empty-frontmatter changeset is this repo's declaration mechanism.scripts/pm/.dispatch-gates.mjslives in objectstack and derives against objectstack's workflows; pointed at objectui paths it prints a confident gate list (check:slot-lookupand five more) of gates that do not exist here. Its--tierline remains usable as a floor; its gate families are not. objectui's real gates come from its own 22 workflows and rootpackage.json. Same foros-verify-lock.sh(container-global entry point in the sibling checkout is established practice) andhalf-state-patrol.yml(objectstack only).packages/app-shellvitest suite takes ~784 s (506 files / 4923 tests) and holds the shared verify lock the entire time, starving every other dev on the machine.⛔ A subagent's
send_laterfires into the PM's session, not its own. Brief devs not to schedule their own check-ins: reading the gate and landing are the PM's job, and the dev's report is the handoff.⛔ AN INSTRUCTION THAT CONTRADICTS A RECORDED RULING IS A DEFECT IN THE INSTRUCTION. Two devs have now been right to disobey a brief: Re-anchor the eight
ADR-0057 D10citations to the framework'sADR-0124 D1— D10 decides Setup-nav capability surfacing, not enforcement location, and the framework's own ADR says so #5701's dev refused a closing keyword the ruling forbade, and RadioField 完全不读 multiple —— spec 允许 radio 带 multiple: true,实际静默渲染成单值 radio 组 #4015's dev refused to re-decide a fork the maintainer had already ruled 13 hours earlier — the PM's brief had stated the opposite of the ruling. ✅ The decision re-read before writing a dispatch is not optional, and it is the PM's failure when it is skipped. Brief devs so that reporting a conflict beats silently resolving it.✅ A claim comment from a different session id blocks, UNLESS it is demonstrably spent — report returned, round closed, card re-queued, and no branch on the remote. The burden is evidence, not assumption, and the evidence goes in the new claim comment so the next reader does not re-derive it.
✅ A GOVERNED-SURFACE CARD SPLITS INTO TWO PRs.⚠️ when the PR author is os-zhuang, GitHub refuses with an author-identity 422 — assign instead and say so in the round report.
docs/adr/**,.claude/**,skills/**,AGENTS.md,CLAUDE.mdstop at draft for human merge. PR 1 = ordinary sites (lands normally, must carryPart of #N, ⛔ never a closing keyword, or the card auto-closes and orphans the governed half); PR 2 = the governed file alone, draft, ⛔ never flipped ready / enqueued / auto-merged. Request review fromos-zhuang;⛔ Still red on
mainand deliberately not this seat's:Test (coverage)and its upload —Test (coverage)is red on every push tomainbecauseCODECOV_TOKENis unset — the four shards are green, the upload is rejected #5436 (CODECOV_TOKENunset) andci.yml'sconcurrencycancels the push-lane coverage job mid-run, so Codecov gets nothing on a merge that is followed by another merge #5422 (ci.ymlconcurrencycancels the push-lane coverage job on a merge train). Both open, bothdomain:devx. ⛔ Do not re-file.Mislabels reported to triage, never changed here:
[Decision]-titled cards sitting inpm:queue([Decision] Should component-registry lookup normalise case? Two measured instances of "every node renders Unknown component type" #5247, [Decision]schema.onNavigateis a function value read off the grid schema — the fifth key #5091's ruling did not cover #5234, [Decision]ObjectMapConfigSchema要不要.strict()—— 类型面的保证只保护 TS 作者,而 AI 产出的 metadata 恰恰不带类型 #5157, [决策] objectui record:details 渲染器的双形状接缝:合成器产 title/descriptor-fields 与 spec 区块形状经裸??缝合,往哪个方向收 #4018, [决策] System Hub bespoke 卡片墙(SystemHubPage)是否按 #3655 选项 C 退场 #3743, [Decision] Should@object-ui/typesship a generated JSON Schema? — the contract an AI author can read before writing #5392); 台账燃尽批次 8/8 · 被 objectstack#4171 阻塞的 any 擦除簇,3 符号——上游解除后处理(objectstack#4115) #3162. plugin-form:navigateOnSuccessis mount-blind and says nothing when its destination is refused — the key has no ruling and its own contract question is still open #5034 carriespm:queuewith an openBlocked-by: objectui#4989— ⛔ verify plugin-form: ObjectForm/WizardForm consume submitBehavior.url against the pre-ruling shape — out-of-contract values silently dropped, same-origin absolutes followed, mount-blind #4989 before treating plugin-form:navigateOnSuccessis mount-blind and says nothing when its destination is refused — the key has no ruling and its own contract question is still open #5034 as available; do not read thepm:queuelabel as clearance.#3965,#2762,#2628,#4795carry non-agent assignees. Afindingis not dispatchable until triage completes first touch — the seat trusts labels and never self-grades.6. Awaiting the maintainer
ADR-0124 D1(#5701) [GOVERNED SURFACE — human merge] #5843 (docs/adr/0036-field-conditional-rules.md, governed surface) — merged 02:06:55Z as commited35c23, and Re-anchor the eightADR-0057 D10citations to the framework'sADR-0124 D1— D10 decides Setup-nav capability surfacing, not enforcement location, and the framework's own ADR says so #5701 closed 02:12:20Z. ✅ No longer awaiting anyone; recorded because the inherited body still listed it as the seat's one human-blocked item.ObjectViewProps.views[].sortdeclaresdirection, but every sort consumer readsorder— a host-supplieddescview silently sorts ascending #5293 · finding(types):TableColumn.typedisagrees three ways — interface declares 8 literals, zod mirror accepts any string, renderer's live read set handles values outside the union via anas anycast #5853 · The withdrawndist/index.d.tsbyte-identity sentence survives verbatim in five released CHANGELOGs — decide whether released records get amended #5913 (allneeds-user-decision,domain:ui).Blocked-by: objectstack#10235. The precondition is three-way (merged upstream / published / pinned here); re-check when the spec pin next advances.