Body is authoritative; title and assignee are derived views. Single writer: the sitting seat PM. Comments are audit only and never carry state.
⛔ CLAUSE ② — the line.
Derived from an authority → repair (not tripped). Hand-typed with no authority to derive from → a new contract decision (TRIPPED).
Cleared: [finding] The SAME drift class one level up: FormViewSpec and FormSectionSpec are each hand-declared twice (console + app-shell), and #5542 only converged the leaf #5596 , finding(app-shell): paramToField is now the LAST private copy of the reference-bearing rule — and its "moves in lockstep with plugin-grid" comment stopped being true #5312 , registry meta 的 defaultChildren 没有任何消费面 —— 设计器拖放只读 defaultProps,11 处声明是惰性的 #5051 , ThemeComponentSchema (type: 'theme') declares a component kind no renderer implements — dead surface, retire alongside objectstack's ThemeSchema authoring-surface retirement #5489 , components: record-picker's emptyText drops the inline-locale-map arm the contract admits, and the audit tracking it (#4163) is closed #5590 , Console FormPage (the standalone /forms and internal FormView renderer) never evaluates visibleWhen/visibleOn — objectui#2212 was fixed in the OTHER form renderer #5594 /finding: apps/console/src/hooks/useBranding.ts is a deprecated hook with zero callers — dead file, not just a dead key #5368 /The three console SDUI preview harnesses author 79 Tailwind classNames inside real page source strings — the practice the shipped lint rule warns on, working only by the coincidence ADR-0065 names as the failure #5470 /finding(cloud-connection): a server-detected bind failure now reads English, while the same failure detected by the panel's own timer reads the locale — two languages for one condition #5054 , finding(types,i18n): after #4167 pinned PRESET_RANGES, two unpinned copies/consumers of the date-range vocabulary remain — the defaultRange TS union and the 10-locale label table #4984 , [finding] ADR-0010 四态锁的词表在本仓有两份手写 union 副本 + 一处三分支无穷尽兜底的横幅,第五态会静默落空 #5024 , finding(types): the zod BaseSchema mirror still declares visible/disabled as boolean and ariaLabel as string, after the TS declarations widened #4605 , finding(types): ComponentRendererProps is the second dual declaration in the same two files as SchemaNode — core's is non-generic, types' is generic #4594 .
Tripped: overrideNotice is produced, read, and declared nowhere — it blocks narrowing the param handlers' action?: any #5611 .
⛔ A clause is not discharged by a gauge that cannot fail (R13, [finding] ComponentInput 有三份结构副本(types 两份 + core 一份)外加一个窄孪生 WidgetInput,而 #4580 的裁定说的是「re-export 而不是 restate」—— 副本之间今天已经有一处分歧 #4972 ). Ruled land ; ruling B rejected because it would retire a route on a broken instrument.
⛔ A RULING'S NAMED HOME CAN BE UNBUILDABLE — honour the ruling's OBSERVABLE requirement, not its literal placement (R15, owner survives as a live field-type in ~13 more code faces after #4814's retirement — including a published Zod enum that still accepts it #4914 ).
The ruling said "Export a single isRetiredFieldType(t) gate from @object-ui/fields." But @object-ui/components is one of the six consumers and fields depends on components (54 source files import from it) — a components → fields import is a package cycle, so the shared table could not live in fields. A second copy inside components would have meant two reportedRetiredTypes sets, so one spelling logs twice — falsifying the ruling's own "fires once" clause on the day it landed.
Resolution: home the table in @object-ui/core (which imports only @object-ui/types) and re-export from @object-ui/fields , so import { isRetiredFieldType } from '@object-ui/fields' resolves and is pinned as a test . The ruling's literal requirement holds; no package gained a dependency.
The dev measured the dependency direction before honouring the wording. That is the order.
⛔⛔ THE BARREL GAUGE — MY OWN RULE WAS TOO NARROW, CORRECTED R14.
I first wrote it as "core/src/index.ts names the symbol zero times, therefore the barrel cannot move." That was true of ComponentInput and accidentally narrow : core/src/index.ts:9 is export type { SchemaNode, ComponentRendererProps } from './types/index.js' — it names finding(types): ComponentRendererProps is the second dual declaration in the same two files as SchemaNode — core's is non-generic, types' is generic #4594 's symbol, and the barrel was byte-identical anyway.
A barrel's emitted .d.ts is byte-identical under any change to a re-exported declaration's SHAPE, whether or not it names the symbol — because neither export * nor export type { X } from '…' restates X's shape. Only the module that DECLARES X can move.
This makes the rule stronger , not weaker: the gauge is vacuous for every re-exported symbol, i.e. the whole published surface of a barrel entry point. Recorded on [finding] #4580's "dist/index.d.ts is byte-identical" justification is a vacuous measurement, and it is written into the repo as evidence #5673 .
⛔ REACHABILITY IS MEASURED THROUGH THE TYPESCRIPT CHECKER, NEVER GREPPED — and the checker itself has a trap (R15, MetadataClient's options.actor is inert against the server after the #7941 attribution ruling #4834 ).
MetadataClient is re-exported as an alias , so its symbol carries flags 2097152 rather than Class. A naive getDeclaredTypeOfSymbol on that alias reads the static side and reports zero methods — a confident, wrong, clean-looking zero. Resolve the alias first. Precedent in the other direction from R14: @object-ui/layout's PageHeader is reachable, via an export * that a text search would have missed ([finding] app-shell 还有第二个 PageHeader,副标题键拼写 description 且无 subtitle —— 与 layout 侧刚收敛的拼写再度分叉 #4761 ).
⛔ record:alert silently ignores the declared visibleWhen gate that its sibling blocks honour — the same defect already closed on the record-header face #5401 IS ORDERED, AND THE ORDER IS THE RULING. Re-ruled 2026-08-22 to option B — "fix the SCOPE, not the slot: bind record into SchemaRenderer's node-level evaluator so visibleWhen finally means what packages/spec/src/ui/page.zod.ts:189 already advertises" — and made a child of umbrella Component-level visibleWhen binds no record on record pages — every record.* predicate fails soft to permanently visible, on every block #5454 , with: "the survey of authored pages … runs first, before the binding change lands ."
R16 dispatches the survey ONLY , hard-fenced against touching SchemaRenderer.tsx. The binding change is a separate, later dispatch gated on what the survey finds.
⚠️ data.* and record.* are two different buckets in the same evaluator — data.* resolves against the data-source adapter (SchemaRenderer's node visibility gate resolves a data.* predicate against the data-source ADAPTER, so a hoisted properties.visible written that way hides the block on every row, silently #5687 ), record.* is unbound at node level (record:alert silently ignores the declared visibleWhen gate that its sibling blocks honour — the same defect already closed on the record-header face #5401 ). A loosely-written sweep surfaces both and they have different correct fixes ; the survey brief requires each site labelled by bucket. Cross-reference posted on SchemaRenderer's node visibility gate resolves a data.* predicate against the data-source ADAPTER, so a hoisted properties.visible written that way hides the block on every row, silently #5687 .
⛔ VERIFY-LOCK SCOPE — ruled R14. packages/app-shell's full 493-file suite is the fallback when a superset cannot be derived, not the default. finding(app-shell): AiChatPage's publicShareBase is a third hand-rolled console-mount resolution — correct today, drift risk under the one-resolver rule #4482 held scripts/pm/os-verify-lock.sh for 927 s with three siblings queued; finding(types): ComponentRendererProps is the second dual declaration in the same two files as SchemaNode — core's is non-generic, types' is generic #4594 and finding(types): the zod BaseSchema mirror still declares visible/disabled as boolean and ariaLabel as string, after the TS declarations widened #4605 each measured exit 99 queue-timeouts behind it. Half of this was a dispatch defect — the brief asked for a provable superset but never said the lock makes over-scoping other agents' problem. Every brief now says it. Batch heavy legs into one acquisition. Precedents: a 105-file reverse-import closure with its over-approximations declared (finding(app-shell): paramToField is now the LAST private copy of the reference-bearing rule — and its "moves in lockstep with plugin-grid" comment stopped being true #5312 ); 215 changed lines mechanically classified as type-only ([finding] The SAME drift class one level up: FormViewSpec and FormSectionSpec are each hand-declared twice (console + app-shell), and #5542 only converged the leaf #5596 ); and R15's owner survives as a live field-type in ~13 more code faces after #4814's retirement — including a published Zod enum that still accepts it #4914 , which took the whole repo minus the docs site deliberately, because a contract change owes the dependents direction and the whole repo is a provable superset of it (43 build / 81 type-check / 47 lint tasks).
⛔ THE MERGE QUEUE VALIDATES NOTHING — 合并队列声称「已强制」却从未产生过一次 merge_group 构建(repo-wide 0),必需集实测不含 4 个 shard / Type Check / Lint —— #3523 的第 3 步从未落地,而 AGENTS.md §9 已按「队列会替你兜住」反转了 auto-merge 禁令 #4986 , open. This makes the by-name check reading LOAD-BEARING, not a double check.
GET /actions/runs?event=merge_group → total_count: 0 , repo-wide, against a control of 3944 for event=push; main's ci.yml does subscribe (lines 50–51). Second, independent evidence added by this seat: all four R13 PRs went enqueued → merged_at in 15–17 s , while the PR lane's run of that same workflow took 5m49s–8m25s for Type Check alone. 合并队列声称「已强制」却从未产生过一次 merge_group 构建(repo-wide 0),必需集实测不含 4 个 shard / Type Check / Lint —— #3523 的第 3 步从未落地,而 AGENTS.md §9 已按「队列会替你兜住」反转了 auto-merge 禁令 #4986 additionally records that the required set excludes the shards, Type Check and Lint, and that AGENTS.md §9 relaxed the auto-merge prohibition on the premise that the queue would catch things.
⛔ 65 PRs have been landed on that premise. While 合并队列声称「已强制」却从未产生过一次 merge_group 构建(repo-wide 0),必需集实测不含 4 个 shard / Type Check / Lint —— #3523 的第 3 步从未落地,而 AGENTS.md §9 已按「队列会替你兜住」反转了 auto-merge 禁令 #4986 holds, the by-name reading below is the ONLY gate. Not this lane's to fix; do not claim 合并队列声称「已强制」却从未产生过一次 merge_group 构建(repo-wide 0),必需集实测不含 4 个 shard / Type Check / Lint —— #3523 的第 3 步从未落地,而 AGENTS.md §9 已按「队列会替你兜住」反转了 auto-merge 禁令 #4986 .
⛔ Build Docs is path-filtered INSIDE the job. On pull_request it diffs base…head limited to apps/site/ and content/; every later step is gated on should_run == 'true'. Same base 9986f9114: Finish the ADR-0080 page-source styling retraction across the remaining 8 prose sites #5665 (edits content/docs/**) → failure, 3m26s ; plugin-calendar README: hold the calendar-view schema block to CalendarViewSchema #5669 (no docs path) → success, 11 s , "No docs-related files changed."
⛔ "A false or stale claim written into a source file AS EVIDENCE" — now four instances in two rounds. [finding] #4580's "dist/index.d.ts is byte-identical" justification is a vacuous measurement, and it is written into the repo as evidence #5673 (finding(types): two competing SchemaNode declarations — core's interface vs types' union #4580 's vacuous docstring, which propagated into [finding] ComponentInput 有三份结构副本(types 两份 + core 一份)外加一个窄孪生 WidgetInput,而 #4580 的裁定说的是「re-export 而不是 restate」—— 副本之间今天已经有一处分歧 #4972 's dispatch obligation); [finding] ADR-0010 四态锁的词表在本仓有两份手写 union 副本 + 一处三分支无穷尽兜底的横幅,第五态会静默落空 #5024 's two comments asserting spec had no z.enum (refuted by a sibling field 32 lines up); [finding] app-shell 还有第二个 PageHeader,副标题键拼写 description 且无 subtitle —— 与 layout 侧刚收敛的拼写再度分叉 #4761 's props docblock still instructing a future reader to do what retire page-header 的 description legacy alias —— 上游 conversion page-header-subtitle-alias 已 live,subtitle ?? description 回退具备退役条件 #3789 already did. All caught by measuring the claim instead of reading it.
⛔ DEDUPE-SEARCH BEFORE FILING — paid out three times today. Two R13 devs and two R14 devs hit the quota and declined to file blind ; the PM filed all six afterwards ([finding] #4580's "dist/index.d.ts is byte-identical" justification is a vacuous measurement, and it is written into the repo as evidence #5673 –[finding] MetadataClient.layered() casts the whole ADR-0010 protection envelope through unchecked, while @objectstack/spec declares Zod for every field of it #5676 , [finding] The anti-drift guard #5680 adds covers BaseSchema only — the ~17 sibling zod mirrors have nothing equivalent, and the class already has two confirmed instances #5684 , [finding] action-param-dialog.tsx hardcodes English in five places while already importing a translation hook for one key #5685 ). And the PM nearly filed the merge-queue finding as new — the search returned 合并队列声称「已强制」却从未产生过一次 merge_group 构建(repo-wide 0),必需集实测不含 4 个 shard / Type Check / Lint —— #3523 的第 3 步从未落地,而 AGENTS.md §9 已按「队列会替你兜住」反转了 auto-merge 禁令 #4986 , open, with more evidence. A finding you are confident about is exactly the one most likely to already exist.
⛔ RETRACTED (R13): "post the report only when it carries an open question or a filing." Reports go to GitHub unconditionally . finding(types,i18n): after #4167 pinned PRESET_RANGES, two unpinned copies/consumers of the date-range vocabulary remain — the defaultRange TS union and the 10-locale label table #4984 's dev was right — "one API call is cheap next to losing the report if this process dies between PR push and the report turn" — and this session has already lost one to a suspend.
⛔ NARROWED (R13): "no model identifier in any pushed artefact" covers only artefacts whose text the dev freely authors. The harness's Co-Authored-By trailer is exempt ; never force-push to strip it.
⛔ A duplicated attribution footer on a PR body is left alone. Keep including it; never edit a body to remove a duplicate.
⛔ Do not round-trip a PR body through this tooling. Per finding(agent-protocol): HTML tags and comments are stripped from every issue/PR body written by an agent — the os-dev-report marker cannot survive, and code samples lose JSX silently #5581 the read path sanitises markdown. finding(app-shell): AiChatPage's publicShareBase is a third hand-rolled console-mount resolution — correct today, drift risk under the one-resolver rule #4482 independently confirmed it with a raw-REST probe: bytes reach GitHub intact. ComponentInput: re-export the one declaration instead of restating it three times #5671 needed Part of → Fixes; the body was left untouched and [finding] ComponentInput 有三份结构副本(types 两份 + core 一份)外加一个窄孪生 WidgetInput,而 #4580 的裁定说的是「re-export 而不是 restate」—— 副本之间今天已经有一处分歧 #4972 closed explicitly instead.
⛔ MY BRIEFS CONTRADICTED THE RECORD FIVE TIMES. From memory instead of the seat post ([finding] Two more comments still name #4163 as the live tracker for the multi-locale label editor; #4163 closed 2026-08-15 #5591 , registerFunction JSDoc uses one name for two entities — the evaluateExpression method and the module-level export #5580 , finding: apps/console/src/hooks/useBranding.ts is a deprecated hook with zero callers — dead file, not just a dead key #5368 ) — fix: a dispatch QUOTES the seat-post line. From a cached list_issues payload, which carries body and NOT comments (registry meta 的 defaultChildren 没有任何消费面 —— 设计器拖放只读 defaultProps,11 处声明是惰性的 #5051 , The three console SDUI preview harnesses author 79 Tailwind classNames inside real page source strings — the practice the shipped lint rule warns on, working only by the coincidence ADR-0065 names as the failure #5470 ) — fix: a cached list payload is not a card read. ✅ Applied R13–R16. R15's reads caught that stack 渲染器读一个从未声明的 spacing 键,catalog 里 135 个节点照着它写 #4890 is not independently dispatchable and that finding: record:alert 是唯一没接 #4075/#4077 行绑定的谓词面 —— 裸 { record } 作用域下 row-action 简写与 data.* 拼法 unbound,fail-soft 使作者门控的横幅永远显示 #4807 had been unblocked by [Decision] Row-predicate spelling contract: does the canon narrow to record.*, or do the bare shorthand and data.* spellings stay? (the uncarried "#4075 step 3" question) #5330 's ruling. R16's reads caught that record:alert silently ignores the declared visibleWhen gate that its sibling blocks honour — the same defect already closed on the record-header face #5401 is not dispatchable as an implementation card at all — its re-ruling puts a survey in front of the change — and that Confirm whether X-Tenant-ID has a reader: the framework derives the tenant from the session, not the header #5279 's hold is discharged : cloud readers of the tenant header exist at packages/service-tenant/src/tenant-context.ts:18 and packages/tenant-router/src/spec/turso-multi-tenant.zod.ts:30, so it is a document-the-contract card, not a removal card .
⛔ MY RECURRING FENCE ERROR (5th at finding(cloud-connection): a server-detected bind failure now reads English, while the same failure detected by the panel's own timer reads the locale — two languages for one condition #5054 ): I fenced the PACKAGE containing the held files instead of the held FILES. ⛔ Standing: fence held PATHS, never the packages that contain them. ✅ Applied R14 ([finding] app-shell 还有第二个 PageHeader,副标题键拼写 description 且无 subtitle —— 与 layout 侧刚收敛的拼写再度分叉 #4761 /finding(app-shell): AiChatPage's publicShareBase is a third hand-rolled console-mount resolution — correct today, drift risk under the one-resolver rule #4482 shared packages/app-shell), R15 (finding: record:alert 是唯一没接 #4075/#4077 行绑定的谓词面 —— 裸 { record } 作用域下 row-action 简写与 data.* 拼法 unbound,fail-soft 使作者门控的横幅永远显示 #4807 /owner survives as a live field-type in ~13 more code faces after #4814's retirement — including a published Zod enum that still accepts it #4914 shared a "predicate" concept on different axes), R16 (all five fences disjoint; record:alert silently ignores the declared visibleWhen gate that its sibling blocks honour — the same defect already closed on the record-header face #5401 carries none because it writes nothing).
⛔ A stop-condition is a PROXY, discharged when the risk it proxies for is measured and disproven — provided the dev says so and puts it up for adjudication (finding: apps/console/src/hooks/useBranding.ts is a deprecated hook with zero callers — dead file, not just a dead key #5368 , finding(cloud-connection): a server-detected bind failure now reads English, while the same failure detected by the panel's own timer reads the locale — two languages for one condition #5054 , [finding] ComponentInput 有三份结构副本(types 两份 + core 一份)外加一个窄孪生 WidgetInput,而 #4580 的裁定说的是「re-export 而不是 restate」—— 副本之间今天已经有一处分歧 #4972 ). R16's Confirm whether X-Tenant-ID has a reader: the framework derives the tenant from the session, not the header #5279 is the same shape one level up: the PM discharged the card's hold by measuring its premise false before dispatch , and said so in the claim comment.
⛔ CONTAINER: Firecracker microVM, suspended and resumed from snapshot. Not OOM, not disk (measured). A resume restores the filesystem and kills the process tree . Three dev-loss shapes, distinguished by git worktree list. ⛔ "The remote branch has no commits" proves nothing was PUSHED, not that nothing EXISTS.
⛔ GITHUB API QUOTA IS SHARED — exhausted FIVE times. One identity, 5000/hr across the PM and 5 devs.
⛔ A control probe must be scoped to the SAME thing, be capable of failing, and MEASURE that it can fail.
The choice of assertion is itself a control decision (finding(app-shell): paramToField is now the LAST private copy of the reference-bearing rule — and its "moves in lockstep with plugin-grid" comment stopped being true #5312 ). Legs failing in disjoint directions separate a pin from its controls (ThemeComponentSchema (type: 'theme') declares a component kind no renderer implements — dead surface, retire alongside objectstack's ThemeSchema authoring-surface retirement #5489 ). A surviving GREEN can carry the scope claim ([finding] ObjectView's override.filter keeps the shape-blind emptiness predicate that #8815 replaced on the two builder write paths — same defect shape, third site #5025 , finding(cloud-connection): a server-detected bind failure now reads English, while the same failure detected by the panel's own timer reads the locale — two languages for one condition #5054 ). Predict each leg's direction in advance. Ablate every probe, not just the doubted ones (refactor(app-shell): one isAiStudioEnabled() accessor for features.aiStudio, replacing two inline spellings #5645 ). A gate test needs an in-test dirty specimen (The three console SDUI preview harnesses author 79 Tailwind classNames inside real page source strings — the practice the shipped lint rule warns on, working only by the coincidence ADR-0065 names as the failure #5470 ).
Void legs are reported, never silently retried — EIGHT instances now (registry meta 的 defaultChildren 没有任何消费面 —— 设计器拖放只读 defaultProps,11 处声明是惰性的 #5051 ×2, finding(cloud-connection): a server-detected bind failure now reads English, while the same failure detected by the panel's own timer reads the locale — two languages for one condition #5054 , The three console SDUI preview harnesses author 79 Tailwind classNames inside real page source strings — the practice the shipped lint rule warns on, working only by the coincidence ADR-0065 names as the failure #5470 , [finding] ComponentInput 有三份结构副本(types 两份 + core 一份)外加一个窄孪生 WidgetInput,而 #4580 的裁定说的是「re-export 而不是 restate」—— 副本之间今天已经有一处分歧 #4972 , finding(app-shell): AiChatPage's publicShareBase is a third hand-rolled console-mount resolution — correct today, drift risk under the one-resolver rule #4482 , finding(types): the zod BaseSchema mirror still declares visible/disabled as boolean and ariaLabel as string, after the TS declarations widened #4605 , owner survives as a live field-type in ~13 more code faces after #4814's retirement — including a published Zod enum that still accepts it #4914 ). ⛔ R15's is the most instructive: leg 2's first attempt was rejected by the dev's own on-disk check, which required the removed text's occurrence count to drop . That check is invalid for an additive mutation — putting 'owner' back into a list injects a string that contains the needle, so the count legitimately stays at 1. The mutation had applied; the instrument was wrong. The check was narrowed to demand the drop only when the needle is not a substring of the replacement, and the leg was re-run under it.
⛔ An instrument returning the same exit code on both legs is unfalsifiable — reject it, don't interpret it (finding(types,i18n): after #4167 pinned PRESET_RANGES, two unpinned copies/consumers of the date-range vocabulary remain — the defaultRange TS union and the 10-locale label table #4984 's TS5112; [finding] components 里有第二个 action param 对话框实现,完全不经共享 evaluator —— 逐选项 visibleWhen 在该 surface 根本不参与;连带 ctx.formValues/data 回退链全仓无生产者 #4758 's TS5011).
⛔ A non-vacuity control belongs in the SAME run as the red leg ([finding] ADR-0010 四态锁的词表在本仓有两份手写 union 副本 + 一处三分支无穷尽兜底的横幅,第五态会静默落空 #5024 's 3 failed | 3 passed; [finding] components 里有第二个 action param 对话框实现,完全不经共享 evaluator —— 逐选项 visibleWhen 在该 surface 根本不参与;连带 ctx.formValues/data 回退链全仓无生产者 #4758 's four green-before).
⛔ A widening on a validator cannot be pinned with currently-valid input (finding(types): the zod BaseSchema mirror still declares visible/disabled as boolean and ariaLabel as string, after the TS declarations widened #4605 ).
⛔ Test whether the pin can go VACUOUS, not just whether it catches a defect — finding(types): the zod BaseSchema mirror still declares visible/disabled as boolean and ariaLabel as string, after the TS declarations widened #4605 's L4 predicted "guard red, main pin vacuously green " and measured exactly that.
⛔ A wrong prediction is not a void leg. finding(types): ComponentRendererProps is the second dual declaration in the same two files as SchemaNode — core's is non-generic, types' is generic #4594 predicted a TS2322 that never appeared, diagnosed the absorption (TS2315 poisons the reference to any), and said so. [finding] app-shell 还有第二个 PageHeader,副标题键拼写 description 且无 subtitle —— 与 layout 侧刚收敛的拼写再度分叉 #4761 's leg A came in narrower than predicted because tsc --noEmit short-circuits — "recorded as observed, not as templated."
Restore under trap … EXIT INT TERM, confirm each mutation on disk by occurrence count, and verify the tree byte-identical afterwards (owner survives as a live field-type in ~13 more code faces after #4814's retirement — including a published Zod enum that still accepts it #4914 : SHA256-MANIFEST-IDENTICAL, git status empty). ⚠️ The root vitest.config.mts aliases every @object-ui/* specifier to the sibling's src/, so ablation suites run the mutated source — no rebuild is owed between legs , and the redness demonstrates it directly.
⛔ MEASUREMENT TRAPS — one shape: the measurement returns the expected answer for the wrong reason.
gzip stores the source filename in its header. 2. Equal byte count ≠ equal content — compare hashes . 3. tsc is composite and skips emit if tsconfig.tsbuildinfo survives — clear dist/ and the build info, which lives outside dist/ (owner survives as a live field-type in ~13 more code faces after #4814's retirement — including a published Zod enum that still accepts it #4914 prints tsbuildinfo left after clean: 0 as a control). 4. grep -c counts LINES — use grep -o | wc -l; grep -F multi-line = multiple patterns; whole-file ≠ region-scoped; line-oriented greps are blind to line-wrapped occurrences; rg skips dot-dirs without --hidden; a census in a built tree without --exclude-dir inflates (51 vs 17); word boundaries are not optional — bare actor gave 972 vs 153 (MetadataClient's options.actor is inert against the server after the #7941 attribution ruling #4834 ); a || echo clean fallback prints a false all-clear from the ERROR path . 5. A stale artefact is silently read later (registry meta 的 defaultChildren 没有任何消费面 —— 设计器拖放只读 defaultProps,11 处声明是惰性的 #5051 ). 6. git checkout BASE -- PATH stages the base content. 7. ⛔ Commit before you ablate.
⛔ RENDER THE UI CHANGE. Static checks cannot see layout. The three console SDUI preview harnesses author 79 Tailwind classNames inside real page source strings — the practice the shipped lint rule warns on, working only by the coincidence ADR-0065 names as the failure #5470 : flex align defaults to start, so an hr with correct computed borders rendered hidden . [finding] ADR-0010 四态锁的词表在本仓有两份手写 union 副本 + 一处三分支无穷尽兜底的横幅,第五态会静默落空 #5024 : three bare && branches with no else rendered the banner title completely empty — {false} renders nothing — while lint, type-check and an exhaustiveness satisfies were all green over it. [finding] components 里有第二个 action param 对话框实现,完全不经共享 evaluator —— 逐选项 visibleWhen 在该 surface 根本不参与;连带 ctx.formValues/data 回退链全仓无生产者 #4758 asserted on the option labels in the open listbox; [finding] app-shell 还有第二个 PageHeader,副标题键拼写 description 且无 subtitle —— 与 layout 侧刚收敛的拼写再度分叉 #4761 asserted DOM position via compareDocumentPosition. R16's Form renderer: "a defaultValues reset is not a user edit" holds only for callers who do NOT memoize the callback #5235 is the next one that needs it — a notification-channel change is only observable from a real mount, edit and reset.
⛔ Verify every citation on origin/main. Outcomes seen: exact; wrong in both directions; stale-but-coincidentally-right; drifted +53 to +103; byte-identical since filing, proven by blob hash (The three console SDUI preview harnesses author 79 Tailwind classNames inside real page source strings — the practice the shipped lint rule warns on, working only by the coincidence ADR-0065 names as the failure #5470 ). owner survives as a live field-type in ~13 more code faces after #4814's retirement — including a published Zod enum that still accepts it #4914 's own line numbers drifted 707/982/1442 → 925/1220/1730 between filing and dispatch.
⛔ The .d.ts criterion is scoped to PROSE-ONLY cards ; .js moves where the package's tsc preserves comments (core, react). check-changeset-presence.mjs is the authority — and it is blind to untracked files, so its first answer on a new test file is wrong until you stage (finding(plugin-calendar): README 的 "Schema API / CalendarView" 块把必填的 events 标成选填,且只列了 CalendarViewSchema 13 个键里的 6 个 #5045 ).
⛔ GOVERNED SURFACES — exactly four: AGENTS.md, CLAUDE.md, .claude/**, docs/adr/**. Sole criterion: does the path start with .claude/. Root skills/** is NOT governed.
A dispatch is a hypothesis; measurement outranks it. Thirty-five devs have now corrected mine — five in R15 (stack 渲染器读一个从未声明的 spacing 键,catalog 里 135 个节点照着它写 #4890 's independence, the alias-vs-class reachability read, the fields → components cycle that made a ruling's literal home unbuildable, the substring-inflated census, and [finding] 响应式词汇的两个零消费表面:useResponsiveConfig 生产零调用者(page.components[].responsive 因此实际未生效)、MobileComponentConfig 零消费者 #4773 's refusal to claim a clean zero on a repo it could not see).
⛔ CONTAINER OPS — five devs share one box. Never pkill -f vitest — verify /proc/PID/cwd, kill by PID . A buffered reporter loses everything on a cap kill; ⚠️ --reporter=basic no longer exists in vitest 4 and aborts before any test executes — use --reporter=verbose. A derived superset must be confirmed to have executed ; ⚠️ apps/console reports paths relative to its own root.
Broken gauges, not failures: check-eager-closure-budget exits 2 locally (CI's budget job passes). check-doc-snippet-types exits 1 until built. check-published-dist-tooling hits the cap — CI owns it.
⚠️ In a fresh worktree a type-check failure is often the unbuilt dependency closure — pnpm --filter '^...' build first.
Footer: session-URL in PR bodies , bare in comments . Package-cwd vitest is refused (pnpm --filter @object-ui/app-shell test 跑的是 @object-ui/console 的 22 个文件,app-shell 自己的 276 个一个没跑,却报绿 #3378 ) — run from the repo root.
list_pull_requests reports merged: false beside a populated merged_at. Trust merged_at.
Merge mechanics: direct merge_pull_request is refused 405 Changes must be made through the merge queue . Path: flip ready → enable_pr_auto_merge (SQUASH). ⚠️ See 合并队列声称「已强制」却从未产生过一次 merge_group 构建(repo-wide 0),必需集实测不含 4 个 shard / Type Check / Lint —— #3523 的第 3 步从未落地,而 AGENTS.md §9 已按「队列会替你兜住」反转了 auto-merge 禁令 #4986 for what that queue does and does not check.
⛔ check_suite.completed is NOT a gate reading. Read gates by name : 22 runs, three always-skipped no-ops (Test (coverage), the unexpanded shard placeholder, dependabot). Green = 19 success + those 3. Shards run 6–11 min at batch 5 on 4 CPUs.
Mislabels reported to triage, not changed here: [Decision]-titled cards in pm:queue ([Decision] Should component-registry lookup normalise case? Two measured instances of "every node renders Unknown component type" #5247 , [Decision] schema.onNavigate is 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 ); 台账燃尽批次 8/8 · 被 objectstack#4171 阻塞的 any 擦除簇,3 符号——上游解除后处理(objectstack#4115) #3162 carries pm:queue with an objectstack blocker in its body.
#3965, #2762 carry non-agent assignees — claimed, never touched.
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_012u2pRjcqAYtoEjgr3wwhnKdomain:ui@objectstack-ai/objectui(execution seat)2. Inherited ledger
Taken over from
session_014zHsbJoTkTZeJQ5DLbRXrE, dark since 2026-08-21T10:43Z. Its three in-flight cards had all merged with nothing recording it — cleared in round 1: #5424/#5555 →needs-user-decision; #5034/#5558 →pm:queue(residual is clause-②; also carriesBlocked-by: #4989, so not dispatchable); #5522/#5559 → comment only. Two deferral targets were phantom cards (404, control-probed).objectstack#10805filed for #5522's orphaned p0 remainder.3. Hot-file serial queue
Round 16 in flight. Held PATHS (never the packages containing them — see §5):
ADR-0057 D10citation has spread to 9 live source sites — the framework anchor it names does not decide that rule #5202.appAccessProbe.test.ts:25is the ninth site, is a correct citation, and is fenced OUT.packages/plugin-form/README.md— finding(plugin-form): README 说字段级className「只在 section-divider 上被读」,实测它经...fieldProps展开落到内置控件的 class 上 #5131 (a one-quantifier fix at :227)onChange,onAction(form_change),onDirtyChange) — Form renderer: "a defaultValues reset is not a user edit" holds only for callers who do NOT memoize the callback #5235packages/auth/src/createAuthenticatedFetch.tsand its package-local edge-contract docs — Confirm whether X-Tenant-ID has a reader: the framework derives the tenant from the session, not the header #5279record:alertsilently ignores the declaredvisibleWhengate that its sibling blocks honour — the same defect already closed on the record-header face #5401 holds NO write fence — it is a read-only survey. ⛔packages/react/src/SchemaRenderer.tsxand the node-level evaluator are untouchable this round (see §5, ordering).Round 15's holds released:
examples/schema-catalog/src/schemas/**+ thestack.tsxrenderer +layout-props-conversion.test.tsx(#4891/#4890),record-alert.tsxand the row-predicate binding path (#4807),packages/data-objectstack/src/metadata-client.ts(#4834),@object-ui/fields' retirement-gate surface and the six field-type predicate faces (#4914),packages/types/src/mobile.ts+useResponsiveConfig(#4773).⛔
packages/core/src/actions/**remains held by the open draft #5644, which is not landing (§6).4. Landing ledger
Rounds 1–15: sixty-eight cards resolved, sixty-five PRs merged. Zero rework landed, zero red CI merged, zero re-runs issued, zero failed escalations. (Derivation, so a successor can re-check rather than inherit a number: R1–14 = 62 cards / 61 PRs; R15 = +6 cards / +4 PRs.) Two landed-and-blocked (#5521, #5544). Three held for the maintainer (#5611, #5344, #5469).
R1–4 (15) · R5 (5) · R6 (5) · R7 (5 PRs / 6 issues) · R8 (5) · R9 (6 cards / 5 PRs) · R10 (5) · R11 (5/5) · R12 (5).
R13 (5): #5469/#5665 HELD on #5668 · #5045/#5669 · #4984/#5670 · #4972/#5671 · #5024/#5672.
R14 (5/5): #4482/#5677 · #4594/#5679 · #4605/#5680 · #4761/#5681 · #4758/#5682.
R15 (6 cards, 4 PRs, 10:33–11:41Z):
record:alertpredicates throughusePredicateRecordContext. Its dev also found that SchemaRenderer's node visibility gate resolvesdata.*against the data-source ADAPTER → filed #5687, now cross-referenced to #5401/#5454 (§5).MetadataClientis re-exported as an ALIAS (symbol flags2097152, notClass), so a naivegetDeclaredTypeOfSymbolreads the static side and reports zero methods. Also the sharpest census trap yet: baregrep -oi actor= 972, word-boundary = 153 — inflated byf-ACTOR-yandref-ACTOR; one file's "14 mentions" were all substrings ofFACTORY.pm:queue+repo:cloud+pm:blocking), per the objectstack#10812 convention.Findings filed this session: #5565, #5567, #5569, #5576, #5577, #5580, #5581, #5590, #5591, #5595, #5596, #5605, #5607, #5608, #5611, #5612, #5613, #5619, #5620, #5623, #5625, #5627, #5630, #5631, #5632, #5633, #5637, #5642, #5647, #5648, #5652, #5654, #5661, #5666, #5667, #5668, #5673, #5674, #5675, #5676, #5678, #5684, #5685, #5687, #5690, #5692, objectstack#10805, objectstack#10928, objectstack#11027 (by a dev), objectstack#11029.
5. Notes
⛔ CLAUSE ② — the line.
paramToFieldis now the LAST private copy of the reference-bearing rule — and its "moves in lockstep with plugin-grid" comment stopped being true #5312, registry meta 的defaultChildren没有任何消费面 —— 设计器拖放只读defaultProps,11 处声明是惰性的 #5051, ThemeComponentSchema (type: 'theme') declares a component kind no renderer implements — dead surface, retire alongside objectstack's ThemeSchema authoring-surface retirement #5489, components:record-picker'semptyTextdrops the inline-locale-map arm the contract admits, and the audit tracking it (#4163) is closed #5590, Console FormPage (the standalone /forms and internal FormView renderer) never evaluates visibleWhen/visibleOn — objectui#2212 was fixed in the OTHER form renderer #5594/finding:apps/console/src/hooks/useBranding.tsis a deprecated hook with zero callers — dead file, not just a dead key #5368/The three console SDUI preview harnesses author 79 Tailwind classNames inside real pagesourcestrings — the practice the shipped lint rule warns on, working only by the coincidence ADR-0065 names as the failure #5470/finding(cloud-connection): a server-detected bind failure now reads English, while the same failure detected by the panel's own timer reads the locale — two languages for one condition #5054, finding(types,i18n): after #4167 pinned PRESET_RANGES, two unpinned copies/consumers of the date-range vocabulary remain — thedefaultRangeTS union and the 10-locale label table #4984, [finding] ADR-0010 四态锁的词表在本仓有两份手写 union 副本 + 一处三分支无穷尽兜底的横幅,第五态会静默落空 #5024, finding(types): the zod BaseSchema mirror still declares visible/disabled as boolean and ariaLabel as string, after the TS declarations widened #4605, finding(types): ComponentRendererProps is the second dual declaration in the same two files as SchemaNode — core's is non-generic, types' is generic #4594.overrideNoticeis produced, read, and declared nowhere — it blocks narrowing the param handlers'action?: any#5611.ComponentInput有三份结构副本(types 两份 + core 一份)外加一个窄孪生WidgetInput,而 #4580 的裁定说的是「re-export 而不是 restate」—— 副本之间今天已经有一处分歧 #4972). Ruled land; ruling B rejected because it would retire a route on a broken instrument.⛔ A RULING'S NAMED HOME CAN BE UNBUILDABLE — honour the ruling's OBSERVABLE requirement, not its literal placement (R15,
ownersurvives as a live field-type in ~13 more code faces after #4814's retirement — including a published Zod enum that still accepts it #4914).The ruling said "Export a single
isRetiredFieldType(t)gate from@object-ui/fields." But@object-ui/componentsis one of the six consumers andfieldsdepends oncomponents(54 source files import from it) — acomponents → fieldsimport is a package cycle, so the shared table could not live infields. A second copy insidecomponentswould have meant tworeportedRetiredTypessets, so one spelling logs twice — falsifying the ruling's own "fires once" clause on the day it landed.The dev measured the dependency direction before honouring the wording. That is the order.
⛔⛔ THE BARREL GAUGE — MY OWN RULE WAS TOO NARROW, CORRECTED R14.
I first wrote it as "
core/src/index.tsnames the symbol zero times, therefore the barrel cannot move." That was true ofComponentInputand accidentally narrow:core/src/index.ts:9isexport type { SchemaNode, ComponentRendererProps } from './types/index.js'— it names finding(types): ComponentRendererProps is the second dual declaration in the same two files as SchemaNode — core's is non-generic, types' is generic #4594's symbol, and the barrel was byte-identical anyway.This makes the rule stronger, not weaker: the gauge is vacuous for every re-exported symbol, i.e. the whole published surface of a barrel entry point. Recorded on [finding] #4580's "dist/index.d.ts is byte-identical" justification is a vacuous measurement, and it is written into the repo as evidence #5673.
⛔ REACHABILITY IS MEASURED THROUGH THE TYPESCRIPT CHECKER, NEVER GREPPED — and the checker itself has a trap (R15, MetadataClient's
options.actoris inert against the server after the #7941 attribution ruling #4834).MetadataClientis re-exported as an alias, so its symbol carries flags2097152rather thanClass. A naivegetDeclaredTypeOfSymbolon that alias reads the static side and reports zero methods — a confident, wrong, clean-looking zero. Resolve the alias first. Precedent in the other direction from R14:@object-ui/layout'sPageHeaderis reachable, via anexport *that a text search would have missed ([finding] app-shell 还有第二个 PageHeader,副标题键拼写description且无subtitle—— 与 layout 侧刚收敛的拼写再度分叉 #4761).⛔
⚠️
record:alertsilently ignores the declaredvisibleWhengate that its sibling blocks honour — the same defect already closed on the record-header face #5401 IS ORDERED, AND THE ORDER IS THE RULING. Re-ruled 2026-08-22 to option B — "fix the SCOPE, not the slot: bindrecordinto SchemaRenderer's node-level evaluator sovisibleWhenfinally means whatpackages/spec/src/ui/page.zod.ts:189already advertises" — and made a child of umbrella Component-levelvisibleWhenbinds norecordon record pages — everyrecord.*predicate fails soft to permanently visible, on every block #5454, with: "the survey of authored pages … runs first, before the binding change lands."R16 dispatches the survey ONLY, hard-fenced against touching
SchemaRenderer.tsx. The binding change is a separate, later dispatch gated on what the survey finds.data.*andrecord.*are two different buckets in the same evaluator —data.*resolves against the data-source adapter (SchemaRenderer's node visibility gate resolves adata.*predicate against the data-source ADAPTER, so a hoistedproperties.visiblewritten that way hides the block on every row, silently #5687),record.*is unbound at node level (record:alertsilently ignores the declaredvisibleWhengate that its sibling blocks honour — the same defect already closed on the record-header face #5401). A loosely-written sweep surfaces both and they have different correct fixes; the survey brief requires each site labelled by bucket. Cross-reference posted on SchemaRenderer's node visibility gate resolves adata.*predicate against the data-source ADAPTER, so a hoistedproperties.visiblewritten that way hides the block on every row, silently #5687.⛔ VERIFY-LOCK SCOPE — ruled R14.
packages/app-shell's full 493-file suite is the fallback when a superset cannot be derived, not the default. finding(app-shell): AiChatPage's publicShareBase is a third hand-rolled console-mount resolution — correct today, drift risk under the one-resolver rule #4482 heldscripts/pm/os-verify-lock.shfor 927 s with three siblings queued; finding(types): ComponentRendererProps is the second dual declaration in the same two files as SchemaNode — core's is non-generic, types' is generic #4594 and finding(types): the zod BaseSchema mirror still declares visible/disabled as boolean and ariaLabel as string, after the TS declarations widened #4605 each measuredexit 99queue-timeouts behind it. Half of this was a dispatch defect — the brief asked for a provable superset but never said the lock makes over-scoping other agents' problem. Every brief now says it. Batch heavy legs into one acquisition. Precedents: a 105-file reverse-import closure with its over-approximations declared (finding(app-shell):paramToFieldis now the LAST private copy of the reference-bearing rule — and its "moves in lockstep with plugin-grid" comment stopped being true #5312); 215 changed lines mechanically classified as type-only ([finding] The SAME drift class one level up: FormViewSpec and FormSectionSpec are each hand-declared twice (console + app-shell), and #5542 only converged the leaf #5596); and R15'sownersurvives as a live field-type in ~13 more code faces after #4814's retirement — including a published Zod enum that still accepts it #4914, which took the whole repo minus the docs site deliberately, because a contract change owes the dependents direction and the whole repo is a provable superset of it (43 build / 81 type-check / 47 lint tasks).⛔ THE MERGE QUEUE VALIDATES NOTHING — 合并队列声称「已强制」却从未产生过一次 merge_group 构建(repo-wide 0),必需集实测不含 4 个 shard / Type Check / Lint —— #3523 的第 3 步从未落地,而 AGENTS.md §9 已按「队列会替你兜住」反转了 auto-merge 禁令 #4986, open. This makes the by-name check reading LOAD-BEARING, not a double check.
GET /actions/runs?event=merge_group→total_count: 0, repo-wide, against a control of 3944 forevent=push;main'sci.ymldoes subscribe (lines 50–51). Second, independent evidence added by this seat: all four R13 PRs wentenqueued→merged_atin 15–17 s, while the PR lane's run of that same workflow took 5m49s–8m25s forType Checkalone. 合并队列声称「已强制」却从未产生过一次 merge_group 构建(repo-wide 0),必需集实测不含 4 个 shard / Type Check / Lint —— #3523 的第 3 步从未落地,而 AGENTS.md §9 已按「队列会替你兜住」反转了 auto-merge 禁令 #4986 additionally records that the required set excludes the shards,Type CheckandLint, and that AGENTS.md §9 relaxed the auto-merge prohibition on the premise that the queue would catch things.⛔ 65 PRs have been landed on that premise. While 合并队列声称「已强制」却从未产生过一次 merge_group 构建(repo-wide 0),必需集实测不含 4 个 shard / Type Check / Lint —— #3523 的第 3 步从未落地,而 AGENTS.md §9 已按「队列会替你兜住」反转了 auto-merge 禁令 #4986 holds, the by-name reading below is the ONLY gate. Not this lane's to fix; do not claim 合并队列声称「已强制」却从未产生过一次 merge_group 构建(repo-wide 0),必需集实测不含 4 个 shard / Type Check / Lint —— #3523 的第 3 步从未落地,而 AGENTS.md §9 已按「队列会替你兜住」反转了 auto-merge 禁令 #4986.
⛔
Build Docsis path-filtered INSIDE the job. Onpull_requestit diffsbase…headlimited toapps/site/andcontent/; every later step is gated onshould_run == 'true'. Same base9986f9114: Finish the ADR-0080 page-source styling retraction across the remaining 8 prose sites #5665 (editscontent/docs/**) → failure, 3m26s; plugin-calendar README: hold the calendar-view schema block to CalendarViewSchema #5669 (no docs path) → success, 11 s, "No docs-related files changed."ActionSchema.condition={ expression, then, else }全仓零消费者:谓词被忽略、then/else 永不派发、零诊断 #3917 dropped from R14's batch (its ruling requires rewriting twocontent/docs/**teaching sites); R15's five all checked; and R16's Confirm whether X-Tenant-ID has a reader: the framework derives the tenant from the session, not the header #5279 is a documentation deliverable, so its brief routes the docs to package-local files and says stop-and-report if they genuinely belong undercontent/docs/**.content/docs/**orapps/site/**untilBuild Docsis red onmain:fsreaches the browser bundle via@objectstack/spec→pg-connection-string#5668 is fixed.Build Docsis red onmain:fsreaches the browser bundle via@objectstack/spec→pg-connection-string#5668 claiming it blocks "every PR based after it". Wrong; title narrowed and a correction posted. It changed a dispatch decision the same hour.⛔ "A false or stale claim written into a source file AS EVIDENCE" — now four instances in two rounds. [finding] #4580's "dist/index.d.ts is byte-identical" justification is a vacuous measurement, and it is written into the repo as evidence #5673 (finding(types): two competing SchemaNode declarations — core's interface vs types' union #4580's vacuous docstring, which propagated into [finding]
ComponentInput有三份结构副本(types 两份 + core 一份)外加一个窄孪生WidgetInput,而 #4580 的裁定说的是「re-export 而不是 restate」—— 副本之间今天已经有一处分歧 #4972's dispatch obligation); [finding] ADR-0010 四态锁的词表在本仓有两份手写 union 副本 + 一处三分支无穷尽兜底的横幅,第五态会静默落空 #5024's two comments asserting spec had noz.enum(refuted by a sibling field 32 lines up); [finding] app-shell 还有第二个 PageHeader,副标题键拼写description且无subtitle—— 与 layout 侧刚收敛的拼写再度分叉 #4761's props docblock still instructing a future reader to do what retire page-header 的 description legacy alias —— 上游 conversion page-header-subtitle-alias 已 live,subtitle ?? description 回退具备退役条件 #3789 already did. All caught by measuring the claim instead of reading it.⛔ DEDUPE-SEARCH BEFORE FILING — paid out three times today. Two R13 devs and two R14 devs hit the quota and declined to file blind; the PM filed all six afterwards ([finding] #4580's "dist/index.d.ts is byte-identical" justification is a vacuous measurement, and it is written into the repo as evidence #5673–[finding]
MetadataClient.layered()casts the whole ADR-0010 protection envelope through unchecked, while@objectstack/specdeclares Zod for every field of it #5676, [finding] The anti-drift guard #5680 adds coversBaseSchemaonly — the ~17 sibling zod mirrors have nothing equivalent, and the class already has two confirmed instances #5684, [finding]action-param-dialog.tsxhardcodes English in five places while already importing a translation hook for one key #5685). And the PM nearly filed the merge-queue finding as new — the search returned 合并队列声称「已强制」却从未产生过一次 merge_group 构建(repo-wide 0),必需集实测不含 4 个 shard / Type Check / Lint —— #3523 的第 3 步从未落地,而 AGENTS.md §9 已按「队列会替你兜住」反转了 auto-merge 禁令 #4986, open, with more evidence. A finding you are confident about is exactly the one most likely to already exist.⛔ RETRACTED (R13): "post the report only when it carries an open question or a filing." Reports go to GitHub unconditionally. finding(types,i18n): after #4167 pinned PRESET_RANGES, two unpinned copies/consumers of the date-range vocabulary remain — the
defaultRangeTS union and the 10-locale label table #4984's dev was right — "one API call is cheap next to losing the report if this process dies between PR push and the report turn" — and this session has already lost one to a suspend.⛔ NARROWED (R13): "no model identifier in any pushed artefact" covers only artefacts whose text the dev freely authors. The harness's
Co-Authored-Bytrailer is exempt; never force-push to strip it.⛔ A duplicated attribution footer on a PR body is left alone. Keep including it; never edit a body to remove a duplicate.
⛔ Do not round-trip a PR body through this tooling. Per finding(agent-protocol): HTML tags and comments are stripped from every issue/PR body written by an agent — the
os-dev-reportmarker cannot survive, and code samples lose JSX silently #5581 the read path sanitises markdown. finding(app-shell): AiChatPage's publicShareBase is a third hand-rolled console-mount resolution — correct today, drift risk under the one-resolver rule #4482 independently confirmed it with a raw-REST probe: bytes reach GitHub intact. ComponentInput: re-export the one declaration instead of restating it three times #5671 neededPart of→Fixes; the body was left untouched and [finding]ComponentInput有三份结构副本(types 两份 + core 一份)外加一个窄孪生WidgetInput,而 #4580 的裁定说的是「re-export 而不是 restate」—— 副本之间今天已经有一处分歧 #4972 closed explicitly instead.⛔ MY BRIEFS CONTRADICTED THE RECORD FIVE TIMES. From memory instead of the seat post ([finding] Two more comments still name #4163 as the live tracker for the multi-locale label editor; #4163 closed 2026-08-15 #5591,
registerFunctionJSDoc uses one name for two entities — theevaluateExpressionmethod and the module-level export #5580, finding:apps/console/src/hooks/useBranding.tsis a deprecated hook with zero callers — dead file, not just a dead key #5368) — fix: a dispatch QUOTES the seat-post line. From a cachedlist_issuespayload, which carriesbodyand NOTcomments(registry meta 的defaultChildren没有任何消费面 —— 设计器拖放只读defaultProps,11 处声明是惰性的 #5051, The three console SDUI preview harnesses author 79 Tailwind classNames inside real pagesourcestrings — the practice the shipped lint rule warns on, working only by the coincidence ADR-0065 names as the failure #5470) — fix: a cached list payload is not a card read. ✅ Applied R13–R16. R15's reads caught thatstack渲染器读一个从未声明的spacing键,catalog 里 135 个节点照着它写 #4890 is not independently dispatchable and that finding: record:alert 是唯一没接 #4075/#4077 行绑定的谓词面 —— 裸 { record } 作用域下 row-action 简写与 data.* 拼法 unbound,fail-soft 使作者门控的横幅永远显示 #4807 had been unblocked by [Decision] Row-predicate spelling contract: does the canon narrow torecord.*, or do the bare shorthand anddata.*spellings stay? (the uncarried "#4075 step 3" question) #5330's ruling. R16's reads caught thatrecord:alertsilently ignores the declaredvisibleWhengate that its sibling blocks honour — the same defect already closed on the record-header face #5401 is not dispatchable as an implementation card at all — its re-ruling puts a survey in front of the change — and that Confirm whether X-Tenant-ID has a reader: the framework derives the tenant from the session, not the header #5279's hold is discharged: cloud readers of the tenant header exist atpackages/service-tenant/src/tenant-context.ts:18andpackages/tenant-router/src/spec/turso-multi-tenant.zod.ts:30, so it is a document-the-contract card, not a removal card.⛔ MY RECURRING FENCE ERROR (5th at finding(cloud-connection): a server-detected bind failure now reads English, while the same failure detected by the panel's own timer reads the locale — two languages for one condition #5054): I fenced the PACKAGE containing the held files instead of the held FILES. ⛔ Standing: fence held PATHS, never the packages that contain them. ✅ Applied R14 ([finding] app-shell 还有第二个 PageHeader,副标题键拼写
description且无subtitle—— 与 layout 侧刚收敛的拼写再度分叉 #4761/finding(app-shell): AiChatPage's publicShareBase is a third hand-rolled console-mount resolution — correct today, drift risk under the one-resolver rule #4482 sharedpackages/app-shell), R15 (finding: record:alert 是唯一没接 #4075/#4077 行绑定的谓词面 —— 裸 { record } 作用域下 row-action 简写与 data.* 拼法 unbound,fail-soft 使作者门控的横幅永远显示 #4807/ownersurvives as a live field-type in ~13 more code faces after #4814's retirement — including a published Zod enum that still accepts it #4914 shared a "predicate" concept on different axes), R16 (all five fences disjoint;record:alertsilently ignores the declaredvisibleWhengate that its sibling blocks honour — the same defect already closed on the record-header face #5401 carries none because it writes nothing).⛔ A stop-condition is a PROXY, discharged when the risk it proxies for is measured and disproven — provided the dev says so and puts it up for adjudication (finding:
apps/console/src/hooks/useBranding.tsis a deprecated hook with zero callers — dead file, not just a dead key #5368, finding(cloud-connection): a server-detected bind failure now reads English, while the same failure detected by the panel's own timer reads the locale — two languages for one condition #5054, [finding]ComponentInput有三份结构副本(types 两份 + core 一份)外加一个窄孪生WidgetInput,而 #4580 的裁定说的是「re-export 而不是 restate」—— 副本之间今天已经有一处分歧 #4972). R16's Confirm whether X-Tenant-ID has a reader: the framework derives the tenant from the session, not the header #5279 is the same shape one level up: the PM discharged the card's hold by measuring its premise false before dispatch, and said so in the claim comment.⛔ CONTAINER: Firecracker microVM, suspended and resumed from snapshot. Not OOM, not disk (measured). A resume restores the filesystem and kills the process tree. Three dev-loss shapes, distinguished by
git worktree list. ⛔ "The remote branch has no commits" proves nothing was PUSHED, not that nothing EXISTS.⛔ GITHUB API QUOTA IS SHARED — exhausted FIVE times. One identity, 5000/hr across the PM and 5 devs.
/rate_limitendpoint here to distinguish. Do not repeat the secondary-limit claim.get_check_runswaiting for green — 22 runs per call. Violated in R13 (Lock banner titles every state that opens it; the ADR-0010 lock vocabulary is declared once #5672 read four times); R14/R15 read once per PR after the shard window.ComponentInput有三份结构副本(types 两份 + core 一份)外加一个窄孪生WidgetInput,而 #4580 的裁定说的是「re-export 而不是 restate」—— 副本之间今天已经有一处分歧 #4972's key counts, barrel shape, zod mirror and consumer census fromorigin/mainat zero API cost — that is what made the clause-② ruling non-circular. R14 did the same for finding(types): ComponentRendererProps is the second dual declaration in the same two files as SchemaNode — core's is non-generic, types' is generic #4594's index signature and consumer census.sleep, never asend_latertrigger — the maintainer is away and cannot approve permission prompts.⛔ A control probe must be scoped to the SAME thing, be capable of failing, and MEASURE that it can fail.
paramToFieldis now the LAST private copy of the reference-bearing rule — and its "moves in lockstep with plugin-grid" comment stopped being true #5312). Legs failing in disjoint directions separate a pin from its controls (ThemeComponentSchema (type: 'theme') declares a component kind no renderer implements — dead surface, retire alongside objectstack's ThemeSchema authoring-surface retirement #5489). A surviving GREEN can carry the scope claim ([finding] ObjectView's override.filter keeps the shape-blind emptiness predicate that #8815 replaced on the two builder write paths — same defect shape, third site #5025, finding(cloud-connection): a server-detected bind failure now reads English, while the same failure detected by the panel's own timer reads the locale — two languages for one condition #5054). Predict each leg's direction in advance. Ablate every probe, not just the doubted ones (refactor(app-shell): oneisAiStudioEnabled()accessor forfeatures.aiStudio, replacing two inline spellings #5645). A gate test needs an in-test dirty specimen (The three console SDUI preview harnesses author 79 Tailwind classNames inside real pagesourcestrings — the practice the shipped lint rule warns on, working only by the coincidence ADR-0065 names as the failure #5470).defaultChildren没有任何消费面 —— 设计器拖放只读defaultProps,11 处声明是惰性的 #5051 ×2, finding(cloud-connection): a server-detected bind failure now reads English, while the same failure detected by the panel's own timer reads the locale — two languages for one condition #5054, The three console SDUI preview harnesses author 79 Tailwind classNames inside real pagesourcestrings — the practice the shipped lint rule warns on, working only by the coincidence ADR-0065 names as the failure #5470, [finding]ComponentInput有三份结构副本(types 两份 + core 一份)外加一个窄孪生WidgetInput,而 #4580 的裁定说的是「re-export 而不是 restate」—— 副本之间今天已经有一处分歧 #4972, finding(app-shell): AiChatPage's publicShareBase is a third hand-rolled console-mount resolution — correct today, drift risk under the one-resolver rule #4482, finding(types): the zod BaseSchema mirror still declares visible/disabled as boolean and ariaLabel as string, after the TS declarations widened #4605,ownersurvives as a live field-type in ~13 more code faces after #4814's retirement — including a published Zod enum that still accepts it #4914). ⛔ R15's is the most instructive: leg 2's first attempt was rejected by the dev's own on-disk check, which required the removed text's occurrence count to drop. That check is invalid for an additive mutation — putting'owner'back into a list injects a string that contains the needle, so the count legitimately stays at 1. The mutation had applied; the instrument was wrong. The check was narrowed to demand the drop only when the needle is not a substring of the replacement, and the leg was re-run under it.defaultRangeTS union and the 10-locale label table #4984's TS5112; [finding] components 里有第二个 action param 对话框实现,完全不经共享 evaluator —— 逐选项 visibleWhen 在该 surface 根本不参与;连带 ctx.formValues/data 回退链全仓无生产者 #4758's TS5011).3 failed | 3 passed; [finding] components 里有第二个 action param 对话框实现,完全不经共享 evaluator —— 逐选项 visibleWhen 在该 surface 根本不参与;连带 ctx.formValues/data 回退链全仓无生产者 #4758's four green-before).any), and said so. [finding] app-shell 还有第二个 PageHeader,副标题键拼写description且无subtitle—— 与 layout 侧刚收敛的拼写再度分叉 #4761's leg A came in narrower than predicted becausetsc --noEmitshort-circuits — "recorded as observed, not as templated."trap … EXIT INT TERM, confirm each mutation on disk by occurrence count, and verify the tree byte-identical afterwards (ownersurvives as a live field-type in ~13 more code faces after #4814's retirement — including a published Zod enum that still accepts it #4914:SHA256-MANIFEST-IDENTICAL,git statusempty).vitest.config.mtsaliases every@object-ui/*specifier to the sibling'ssrc/, so ablation suites run the mutated source — no rebuild is owed between legs, and the redness demonstrates it directly.⛔ MEASUREMENT TRAPS — one shape: the measurement returns the expected answer for the wrong reason.
gzipstores the source filename in its header. 2. Equal byte count ≠ equal content — compare hashes. 3.tscis composite and skips emit iftsconfig.tsbuildinfosurvives — cleardist/and the build info, which lives outsidedist/(ownersurvives as a live field-type in ~13 more code faces after #4814's retirement — including a published Zod enum that still accepts it #4914 printstsbuildinfo left after clean: 0as a control). 4.grep -ccounts LINES — usegrep -o | wc -l;grep -Fmulti-line = multiple patterns; whole-file ≠ region-scoped; line-oriented greps are blind to line-wrapped occurrences;rgskips dot-dirs without--hidden; a census in a built tree without--exclude-dirinflates (51 vs 17); word boundaries are not optional — bareactorgave 972 vs 153 (MetadataClient'soptions.actoris inert against the server after the #7941 attribution ruling #4834); a|| echo cleanfallback prints a false all-clear from the ERROR path. 5. A stale artefact is silently read later (registry meta 的defaultChildren没有任何消费面 —— 设计器拖放只读defaultProps,11 处声明是惰性的 #5051). 6.git checkout BASE -- PATHstages the base content. 7. ⛔ Commit before you ablate.--removeCommentsproves zero program semantics — INVALID for shipped-bytes claims..d.tsand.jsgauges answer different questions and both are worth reading. [finding] components 里有第二个 action param 对话框实现,完全不经共享 evaluator —— 逐选项 visibleWhen 在该 surface 根本不参与;连带 ctx.formValues/data 回退链全仓无生产者 #4758: declaration emit byte-identical while CI's Bundle Analysis showedcomponents506.21 → 506.84 KB — the correct signature for "rebind, not delete". Inverse of registry meta 的defaultChildren没有任何消费面 —— 设计器拖放只读defaultProps,11 处声明是惰性的 #5051, where the bundle gauge caught a shrink the report's own sweep missed.ownersurvives as a live field-type in ~13 more code faces after #4814's retirement — including a published Zod enum that still accepts it #4914 read it the third way: a whole-tree.d.tsmanifest moving exactly four entries, 166 → 167 files, with the delta on the public package purely additive.⛔ RENDER THE UI CHANGE. Static checks cannot see layout. The three console SDUI preview harnesses author 79 Tailwind classNames inside real page
sourcestrings — the practice the shipped lint rule warns on, working only by the coincidence ADR-0065 names as the failure #5470: flexaligndefaults tostart, so anhrwith correct computed borders rendered hidden. [finding] ADR-0010 四态锁的词表在本仓有两份手写 union 副本 + 一处三分支无穷尽兜底的横幅,第五态会静默落空 #5024: three bare&&branches with noelserendered the banner title completely empty —{false}renders nothing — while lint, type-check and an exhaustivenesssatisfieswere all green over it. [finding] components 里有第二个 action param 对话框实现,完全不经共享 evaluator —— 逐选项 visibleWhen 在该 surface 根本不参与;连带 ctx.formValues/data 回退链全仓无生产者 #4758 asserted on the option labels in the open listbox; [finding] app-shell 还有第二个 PageHeader,副标题键拼写description且无subtitle—— 与 layout 侧刚收敛的拼写再度分叉 #4761 asserted DOM position viacompareDocumentPosition. R16's Form renderer: "a defaultValues reset is not a user edit" holds only for callers who do NOT memoize the callback #5235 is the next one that needs it — a notification-channel change is only observable from a real mount, edit and reset.⛔ Verify every citation on
origin/main. Outcomes seen: exact; wrong in both directions; stale-but-coincidentally-right; drifted +53 to +103; byte-identical since filing, proven by blob hash (The three console SDUI preview harnesses author 79 Tailwind classNames inside real pagesourcestrings — the practice the shipped lint rule warns on, working only by the coincidence ADR-0065 names as the failure #5470).ownersurvives as a live field-type in ~13 more code faces after #4814's retirement — including a published Zod enum that still accepts it #4914's own line numbers drifted 707/982/1442 → 925/1220/1730 between filing and dispatch.⛔ The
.d.tscriterion is scoped to PROSE-ONLY cards;.jsmoves where the package'stscpreserves comments (core,react).check-changeset-presence.mjsis the authority — and it is blind to untracked files, so its first answer on a new test file is wrong until you stage (finding(plugin-calendar): README 的 "Schema API / CalendarView" 块把必填的events标成选填,且只列了 CalendarViewSchema 13 个键里的 6 个 #5045).⛔ GOVERNED SURFACES — exactly four:
AGENTS.md,CLAUDE.md,.claude/**,docs/adr/**. Sole criterion: does the path start with.claude/. Rootskills/**is NOT governed.A dispatch is a hypothesis; measurement outranks it. Thirty-five devs have now corrected mine — five in R15 (
stack渲染器读一个从未声明的spacing键,catalog 里 135 个节点照着它写 #4890's independence, the alias-vs-class reachability read, thefields → componentscycle that made a ruling's literal home unbuildable, the substring-inflated census, and [finding] 响应式词汇的两个零消费表面:useResponsiveConfig 生产零调用者(page.components[].responsive 因此实际未生效)、MobileComponentConfig 零消费者 #4773's refusal to claim a clean zero on a repo it could not see).⛔ CONTAINER OPS — five devs share one box. Never⚠️ ⚠️
pkill -f vitest— verify/proc/PID/cwd, kill by PID. A buffered reporter loses everything on a cap kill;--reporter=basicno longer exists in vitest 4 and aborts before any test executes — use--reporter=verbose. A derived superset must be confirmed to have executed;apps/consolereports paths relative to its own root.Broken gauges, not failures:
check-eager-closure-budgetexits 2 locally (CI's budget job passes).check-doc-snippet-typesexits 1 until built.check-published-dist-toolinghits the cap — CI owns it.type-checkfailure is often the unbuilt dependency closure —pnpm --filter '^...' buildfirst.Footer: session-URL in PR bodies, bare in comments. Package-cwd
vitestis refused (pnpm --filter @object-ui/app-shell test跑的是 @object-ui/console 的 22 个文件,app-shell 自己的 276 个一个没跑,却报绿 #3378) — run from the repo root.list_pull_requestsreportsmerged: falsebeside a populatedmerged_at. Trustmerged_at.Merge mechanics: direct⚠️ See 合并队列声称「已强制」却从未产生过一次 merge_group 构建(repo-wide 0),必需集实测不含 4 个 shard / Type Check / Lint —— #3523 的第 3 步从未落地,而 AGENTS.md §9 已按「队列会替你兜住」反转了 auto-merge 禁令 #4986 for what that queue does and does not check.
merge_pull_requestis refused 405Changes must be made through the merge queue. Path: flip ready →enable_pr_auto_merge(SQUASH).⛔
check_suite.completedis NOT a gate reading. Read gates by name: 22 runs, three always-skippedno-ops (Test (coverage), the unexpanded shard placeholder,dependabot). Green = 19 success + those 3. Shards run 6–11 min at batch 5 on 4 CPUs.Mislabels reported to triage, not changed here:
[Decision]-titled cards 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); 台账燃尽批次 8/8 · 被 objectstack#4171 阻塞的 any 擦除簇,3 符号——上游解除后处理(objectstack#4115) #3162 carriespm:queuewith an objectstack blocker in its body.#3965,#2762carry non-agent assignees — claimed, never touched.6. Awaiting the maintainer
overrideNoticeis produced, read, and declared nowhere — it blocks narrowing the param handlers'action?: any#5611 / PR feat(core): declareoverrideNoticeonActionDef, then narrow both param handlers'action?: any#5644 — clause ② tripped. Green and verified; held because it declaresoverrideNoticeonActionDef, which is closed and reachable, so the key is atscerror today and legal after. Decide: accept the widening (feat(core): declareoverrideNoticeonActionDef, then narrow both param handlers'action?: any#5644 lands unchanged), or a narrower host-composed shape at the dispatch seam.accessorKeycolumn re-saves a spellingobject-gridno longer renders #5344 — a data-shape decision with one factual question in front of it. Measured: the "harmless round-trip" is a closed loop —patchIdentityre-emits the spelling it found, so a non-canonical column is refused before and after any inspector edit. The ruling needed: is there a known population of pre-examples/schema-catalog: 13 个 grid 示例用了未声明的cols键,列数被静默丢弃 —— 要 3/4 列的示例在 docs 站实际渲染成 2 列 #4001 stored view documents carryingaccessorKeycolumns? Yes → A+D. No → D alone. In-repo population measured zero.Build Docsis red onmain:fsreaches the browser bundle via@objectstack/spec→pg-connection-string#5668.user.roles— role-addressed approvals andrequiredRolesgates degrade silently at protocol 17 #5424 · RadioField 完全不读 multiple —— spec 允许 radio 带 multiple: true,实际静默渲染成单值 radio 组 #4015 (recommend C, fall back to B) ·holdsStudioAccessis unreachable from@object-ui/app-shell, so the library's surfaces cannot share the console's one definition of "platform operator" #5576 (lean B) · [finding]maxToolRoundtripsis an authorable, documented chatbot key that reaches nothing — useObjectChat destructures it and never reads it #5605 · skills/objectui/guides/i18n.md 两处把 label 规则归给@objectstack/specv4,仓内实测 ^17.0.0 —— agent 面上 13 个 major 的版本化石 #5081 · objectstack#10928 · objectstack#11029 · finding:ThemeSwitcherSchema/ThemePreviewSchemaare the same dead component kind #5489 retires —theme-switcherandtheme-previeware registered by nothing either #5647 · [finding] A THIRD hand-written FormViewSchema mirror survives inpackages/react's spec bridge, and it has drifted on three keys #5596 just measured #5652 · burn-down: 119 ledgered DOM-attribute leaks inpackages/components/src/renderers/**, grouped by mechanism #5632 ·ui:iconreads the SDUI identity keynameas its lucide icon name, so any icon node that authorsnamerenders nothing at all #5631 / Nothing checks that anicon:literal reaching a record-reading lucide resolver is a liveiconskey — four hand-copied resolvers, four local pins, no gate over the population #5633 · components:record-picker'slabelandplaceholderdrop the same inline-locale-map armemptyTextjust stopped dropping — one throws, the other silently renders English or nothing #5637 ·warnOnUnknownActionKeys's dev-console message states a fact step 3 retired, and points the author at the wrong file #5642 ·content/docs/core/theme-schema.mdxteaches a schema that does not exist — six independent falsehoods, now including thetype: 'theme'kind #5489 retires #5648 · finding(app-shell):ActionParamDialog'sisLookupParamrestates the picker family over RAW param spellings, so a degradedmaster_detailparam loses the #3405 affordances #5654 ·kind:'html'page source loses the space between a text run and an adjacent inline element —A <strong>x</strong> pagerenders asAxpage#5661 · A file-header comment inpackages/components/srcDOES project into the published.d.ts— #5461's changeset asserts the opposite, and shipped a@object-ui/componentsdoc change with no entry #5666 · finding(types/plugin-calendar):CalendarViewSchemadeclares 9 of its 13 keys that thecalendar-viewrenderer never reads — includingevents, its only required key, which the renderer deliberately drops #5667.Build Docsis red onmain:fsreaches the browser bundle via@objectstack/spec→pg-connection-string#5668 —Build Docsred onmain;fsreaches the browser bundle via@objectstack/spec→pg-connection-string. Blocks any PR touchingcontent/docs/**orapps/site/**. Cross-referenced to 合并队列声称「已强制」却从未产生过一次 merge_group 构建(repo-wide 0),必需集实测不含 4 个 shard / Type Check / Lint —— #3523 的第 3 步从未落地,而 AGENTS.md §9 已按「队列会替你兜住」反转了 auto-merge 禁令 #4986, which is why four merges carried it forward unnoticed.PluginComponentInputis a published name with zero consumers, and after #4972 it is a pure alias ofComponentInput#5674 · [finding]WidgetInputrestates the input vocabulary a third time, and the deferral tracking it is about to be closed with #4972 #5675 · [finding]MetadataClient.layered()casts the whole ADR-0010 protection envelope through unchecked, while@objectstack/specdeclares Zod for every field of it #5676 · finding(app-shell): the injected<base href>'s trailing slash is an unstated invariant of the console-mount resolver family #5678 · [finding] The anti-drift guard #5680 adds coversBaseSchemaonly — the ~17 sibling zod mirrors have nothing equivalent, and the class already has two confirmed instances #5684 · [finding]action-param-dialog.tsxhardcodes English in five places while already importing a translation hook for one key #5685 · SchemaRenderer's node visibility gate resolves adata.*predicate against the data-source ADAPTER, so a hoistedproperties.visiblewritten that way hides the block on every row, silently #5687 (thedata.*/record.*split — read it besiderecord:alertsilently ignores the declaredvisibleWhengate that its sibling blocks honour — the same defect already closed on the record-header face #5401/Component-levelvisibleWhenbinds norecordon record pages — everyrecord.*predicate fails soft to permanently visible, on every block #5454) · finding: 9 catalogflexnodes still hand-write spacing asspace-x-*, the one spelling #4891's sweep deliberately left behind #5690 · finding(plugin-dashboard): two more private copies of the reference-bearing field family — #5312's "LAST private copy" claim is false #5692 (plugin-dashboardholds two more private copies of the reference-bearing field family, in a non-subset relation with@object-ui/core'sEXPANDABLE_FIELD_TYPESin both directions; this also falsifies finding(app-shell):paramToFieldis now the LAST private copy of the reference-bearing rule — and its "moves in lockstep with plugin-grid" comment stopped being true #5312's closing claim thatparamToFieldwas the last such copy).