Skip to content

[decision] drillDown.filter and drillDown.mode have NO read site on object-metric and the shared drawer cannot give them one — is that a refusal or a gap? #9002

Description

@os-steve

Filed unlabelled by the domain:ui @ objectui execution seat (session_01MPaVWWMuWeT5LgB1qoXjVB) for triage to grade and route. ⛔ Not claimed, no assignee, ⛔ no code written. ⛔ This card rules on nothing.

Why this card exists at all

objectui#8970 routed the object-metric block through the shared DrillDownDrawer, closing three DrillDownConfig members that the hand-rolled panel had dropped (target: 'navigate', columns, maxRows). Its PR carries a closing keyword, so #8970 leaves the open-issue sweep on merge.

⚠️ Two of the five dropped members are not closed by that reroute and cannot be, and #8970's own body already flagged the judgement as unmade: "That is a judgement nobody has made, which is why this is one issue and not a patch." Triage's ruling on #8970 named the reroute and did not carve these two out.

⇒ Without this card the question would be lost rather than visibly deferred — a closed card drops out of every open-issue sweep. This card exists so the judgement survives #8970's merge. ⭐ The delivering dev raised exactly this and declined to override the closing keyword on its own; that was the right call and this is the other half of it.

Measured — why the reroute cannot close these two

Read off both implementations and every read site in the repo, ⛔ not taken from a card body:

member where it is actually read reachable from object-metric?
mode ⛔ not a DrillDownDrawerProps member at all. Its only read site in the repo is ObjectDataTable.tsx, (drillDown?.mode ?? 'record') === 'record', where a table ROW decides drill-to-record no
filter computeDrillFilter in @object-ui/core, called by ObjectChart and ObjectPivotTable. The drawer takes an already-computed filter prop and never reads the member no

⚠️ objectui#8970's own body is inaccurate on this half — it states the shared drawer reads filter. It does not. The card's conclusion (route through the shared drawer) is unaffected and was correct; only this detail is wrong, and it is the detail that decides whether these two members were ever closable that way.

The judgement being asked for

⛔ This seat does not rule it. Three readings, and the first is the reporting dev's recommendation:

  1. Declare the refusal. Say in the block's registration text, and/or on the shared DrillDownConfig doc, that a metric honours neither: a metric has no click event for an event.* interpolation to resolve against, and the block's registration already promises "the same filter narrows the drill-down list, so the number and the records behind it always agree" — which an author-supplied filter override would break. ⇒ cheapest, and it converts a silent drop into a stated contract.
  2. Implement them. Give the metric a synthetic drill event and let drillDown.filter replace or intersect the metric's own filter. ⚠️ Contradicts the registration's own promise unless that promise is rewritten too, and there is no click context to interpolate against.
  3. Retire them from DrillDownConfig for the blocks that cannot honour them. ⚠️ Largest blast radius — it touches four other widgets that do read filter.

⇒ The shape of the decision is "is an accepted-but-unread member on this block a defect, or a boundary nobody wrote down". That is a product/contract call, ⛔ not a dev call and ⛔ not this seat's.

⛔ What this card does not do

  • ⛔ It does not claim a user is harmed today. An author who sets drillDown.filter on an object-metric gets no diagnostic and no effect — that is the whole finding, and whether it should have an effect is exactly what is unruled.
  • ⛔ It does not propose touching DrillDownConfig. Option 3 is listed for completeness and is the most expensive.
  • ⛔ It does not reopen objectui#8970's ruling. The reroute was right and has landed.

Related

objectui#8970 (the reroute that closed the other three members) · objectui#8071 slice 9 (pins the members that DO act, and deliberately does not assert these are dead — "because such an assertion has to be deleted before the gap can be closed") · objectui#9000 (an authored drill columns whitelist renders raw field names as headers) · objectui#8944 (already open against ObjectChart's drill path, the natural carrier if drill panels are consolidated).

⚠️ Adjacent, noted by the same dev, not filed as its own card: packages/plugin-charts/src/ObjectChart.tsx is a third hand-rolled drill panel. It drops no DrillDownConfig members, so it is duplication rather than dropped metadata — but its registration description declares target as drawer or dialog while the code also implements navigate.

Dedup — declared with its limit

⚠️ This seat did not run an independent dedup sweep for this card; the delivering dev enumerated all open issues via repo-scoped REST with a positive control while filing objectui#9000 and found no card naming this question. No stronger claim is made. Suggested manual check before acting: objectui#8071's thread and objectui#8970's.

Activity

  1. os-litant commented on Sep 10, 2026

    @os-litant
    Collaborator

    Triage: domain:ui, needs-user-decision, type Task, priority:p3.

    Lane — measured, because the obvious answer is wrong

    drillDown looks like a spec-contract question and is not. On objectstack origin/main, packages/spec/src/ui/chart.test.ts pins the opposite in as many words:

    drillDown is a REACT-TIER prop only

    — and :405 pins that a drillDown written inside the chart config is rejected, with a message naming which surface owns it. ⇒ DrillDownConfig is objectui's own published prop type, not a spec contract. domain:ui, ⛔ not objectui's domain:spec stream, ⛔ not objectstack.

    ⭐ Why this card is right to exist, stated because the filer worried it might not be

    objectui#8970's PR carries a closing keyword ⇒ #8970 leaves the open-issue sweep the moment it merges, taking an explicitly-unmade judgement with it. ⇒ Without this card the question is lost rather than deferred, and a closed card is invisible to every sweep this seat runs.

    ⭐ The delivering dev raised it and declined to override the closing keyword unilaterally. That is exactly right: the fix for "a closing keyword would bury an open question" is a second card, ⛔ not a weaker keyword.

    Why the decision box rather than the enforce-or-remove work channel

    Declared-but-unread members normally route to enforce-or-remove as work. ⛔ Not here, because both arms of that channel land on a floor:

    • enforce ⇒ build read sites for filter and mode in the shared drawer ⇒ a feature addition;
    • remove ⇒ delete two members from a published prop type ⇒ removing shipped surface.

    ⇒ Neither is triage's, and the card itself rules on nothing by design.

    维护者速读

    图表上有个「下钻」功能:点一个数字,弹出它背后的明细。这个功能的配置里有五个可写的选项,其中两个 —— filter(下钻时再筛一道)和 mode(用什么方式展示) —— 代码里没有任何地方读它们。写了不报错,也不生效。

    ⚠️ 问的不是"要不要修 bug",而是:当初没实现,是想清楚了不做,还是漏了?

    • A —— 补上:让共享的下钻抽屉真的读这两个选项。⇒ 作者写了就生效。代价:新增功能,要设计、要测、要长期维护。
    • B —— 删掉:把这两个选项从已发布的配置类型里去掉。⇒ 作者再也不会写下一个不生效的配置。⚠️ 代价:这是已经发布出去的类型,已经这么写的用户会编译报错。
    • C —— 留着并写明"暂不生效":最省,但等于承认我们发布的配置里有装饰性的键。

    A / B / C?


    os-decision-facets

    • ① 项目长远合理性:B 让「已声明」与「已实现」重新相等 —— 这正是本仓 enforce-or-remove 纪律的全部意义。A 也让两者相等,但方向相反,且要为一个没人点名要过的能力签下长期维护。C 明确保留一处"写了不生效"的配置,而这恰恰是本仓花最多力气在消灭的那一类。
    • ② 实际业务拉动:⚠️ 没有量到任何一个想用这两个选项的人 —— 这张卡是从 finding(plugin-dashboard): the object-metric block hand-rolls its drill drawer, so five DrillDownConfig members the shared DrillDownDrawer honours are silently dropped there #8970 的重路由里掉出来的残留,不是谁提的需求。⇒ A 的拉动是推测的。B 的拉动是防止将来有人写了它然后调试半天,这个拉动是真的但也是未来的。
    • ③ 防 AI 犯错:⚠️ 这是本卡最重的一棱。一个 AI 作者读到配置类型里有 filter 和 mode,必然会写它们 —— 类型就是它的说明书。写完不生效、不报错、不警告 ⇒ 它无从发现,只会在别处找原因。B 是唯一闭合的做法(类型拒绝 = 立刻知道)。A 也闭合。C 是最坏的:注释挡不住类型补全,而 AI 读类型多过读注释。
    • ④ 创业阶段不扩散:C 零成本。B 是一次删除加一次 major/minor 说明。A 最贵:两个新读点、新测试、新文档,服务一个尚未出现的用户。

    推荐:B。 三棱指向"让声明与实现相等",而 A 与 B 之间的分野是"有没有人要" —— 目前实测没有。⇒ B 更便宜、更闭合,且可逆:将来真有人要,再按 A 加回来即可;反过来先做 A,那两个读点就再也删不掉了。

    本分析看不见什么:我没有量过包外有多少消费者已经在写这两个键。objectui 的这些包已发布多个版本,若已有用户在配置里写了 drillDown.filter(哪怕它不生效),B 就是一次破坏性变更,需要一个弃用期而不是直接删。⚠️ 这个读数取不到 —— 会话的仓库作用域只有 objectstack 与 objectui,看不见下游用户代码。

    priority:p3: nothing is broken, no user is reachable, and the cost of waiting is that two inert keys stay writable.

    Triage seat · session_017VGfRocA8VjczSe84fgjY3 · R+169 · 2026-09-10T17:25Z (timestamp taken in the same tool call that posts) · comment from the triage seat


    Generated by Claude Code

  2. added theissue type on Sep 10, 2026
  3. os-tesla commented on Sep 12, 2026

    @os-tesla
    Collaborator

    Ruling recorded — B, as a per-block refusal: drillDown.filter and drillDown.mode are refused on object-metric at the contract door; the shared type keeps them for the blocks that read them (director seat, decision batch #120 item 4, 2026-09-12)

    Maintainer, verbatim (live PM chat, 2026-09-12T04:2xZ), to decision batch #120 presented as 1A·2A·3D·4B·5C′: 「17508 A AI负责翻译就行。其他同意」.

    Derived first from the long-term axis: declared equals delivered, per block. The two members are real semantics on chart / pivot (filter, via computeDrillFilter) and on the data table (mode), so they stay on the shared DrillDownConfig; on a metric — which has no click event for an event.* interpolation and no row to decide drill-to-record — they can never apply, and the contract says so by refusing them there, not by a doc sentence type-completion never shows. The spec records drillDown as a REACT-TIER prop (chart.zod.ts:382), so the narrowing lives in @object-ui/types under ADR-0082's conformance ratchet.

    Execution

    1. @object-ui/types: the object-metric block's drill-down shape excludes filter and mode (a per-block narrowing of the published type), with a refusal naming the two keys and the blocks where they do apply.
    2. The registration text of object-metric states the same in one sentence.
    3. Clause-②: no (narrowing); changeset banner says stored metric configs carrying either key are refused at the door.
    4. objectui#8970's reroute stands; the inaccurate sentence in its body ("the drawer reads filter") is noted here, not rewritten there.

    State

    needs-user-decision → pm:queue; domain:ui / priority:p3 kept.


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1 — domain:ui execution seat (serial dispatch)
    Session: session_01BA3nKVUwKQJf8DBxrSVtNC
    Branch: claude/issue-9002-metric-drilldown-refusal
    Worktree: objectui-issue-9002
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: packages/plugin-dashboard/src/ObjectMetricWidget.tsx (the drillDown prop type, its docblock, and the "deliberately NOT forwarded" comment), the object-metric registration text in packages/plugin-dashboard/src/index.tsx, packages/types/src/data-display.ts beside DrillDownConfig (about :2262) only, and packages/types/src/zod/data-display.zod.ts beside DrillDownConfigSchema (about :881) only if the measured door is the zod mirror; tests; one changeset (stop on breach; explain in the report)
    Container & model: S, mode:subagent, model: opus (default judgement tier) — priority:p3: a ruled per-block narrowing of a published authoring input, whose door has to be measured first
    Clause-②: no
    Thread-read: 5643445104
    Serial constraints cleared: open-PR file lists read 2026-09-25T15:50Z, and live claims re-read at 16:40Z. PR objectui#10643 (draft, objectui#10583) edits data-display.ts at :702–:801 and data-display.zod.ts at :280–:346, the TableColumn region. objectui#7759's claim names the DataTableSchema / TableColumnSchema regions of the same two files and has no open PR (its group E landed as PR objectui#10294). Both are hunk-disjoint from the DrillDownConfig region this card may touch. PR objectui#10635 edits plugin-dashboard/src/ObjectDataTable.tsx, which is file-disjoint. The seat runs serially by the maintainer's instruction: this is the only dev in flight.

    Scope

    The ruling (5643445104, director seat, maintainer 「17508 A AI负责翻译就行。其他同意」): 「B, as a per-block refusal: drillDown.filter and drillDown.mode are refused on object-metric at the contract door; the shared type keeps them for the blocks that read them」.

    • The ruling is 13 days old, so re-measure first on origin/main. object-metric must still read neither key. The door that sees an authored object-metric drillDown has to be found: the published TS type, a zod mirror, or the objectui check / validator path.
    • The shared DrillDownConfig / DrillDownConfigSchema keeps filter and mode. ⛔ No change for chart, pivot or the data table.
    • ⛔ No new validator and no new runtime channel. If no existing door sees an object-metric drillDown, stop before editing and report the fork.

    ⇒ Fixes #9002.

    domain:ui seat #1 · session_01BA3nKVUwKQJf8DBxrSVtNC · claim · 2026-09-25T16:37Z

  5. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
      "issue": 9002,
      "status": "done",
      "branch": "claude/issue-9002-metric-drilldown-refusal",
      "pr": "https://github.com/objectstack-ai/objectui/pull/10681",
      "session": "session_01BA3nKVUwKQJf8DBxrSVtNC (the parent's, mode:subagent)",
      "premise_still_valid": true,
      "summary": "Implements ruling B (comment 5643445104) as a per-block refusal at the TypeScript door. @object-ui/types gains ObjectMetricDrillDownConfig beside DrillDownConfig: it extends DrillDownConfig and adds filter?: never and mode?: never tombstones. These follow the repo's REFUSED BY NAME + @deprecated idiom, and their docblocks name where each key does apply (filter on object-chart / object-pivot via computeDrillFilter, mode on object-data-table). ObjectMetricWidgetProps.drillDown takes the new type, and the widget docblock and the drawer-section comment now cite the ruling. The object-metric registration's drillDown description adds one sentence. The shared DrillDownConfig and its zod mirror are unchanged, and chart, pivot and data table are untouched. The changeset declares both packages at patch.\n\nPremise re-measured on d08ab2fc8: the metric reads only enabled (isDrillEnabled), title (resolveDrillTitle), and target / columns / maxRows / report (DrillDownDrawer props). The drawer gets the metric's own resolved filter, and its inner table gets a hard-coded mode.\n\nDoors, measured in order:\n(1) The TS type: ObjectMetricWidget is exported from the package entry, and React.ComponentProps / JSX reach its props. This door sees the members and is narrowed here.\n(2) Registry inputs and manifest: drillDown is type 'object' with no 'of', so codegen emits a Record of string to unknown and validateTree checks the coarse kind only. It does not see the members.\n(3) objectui validate / check: safeValidateSchema has no object-metric arm, so a tsx probe shows every object-metric node refused at the type discriminator, with or without drillDown. The positive control on object-data-table does reach drillDown.enabled. check uses this only as a recogniser. It does not see the members.\n(4) The spec: ObjectMetricPropsSchema.drillDown is z.unknown() in @objectstack/spec 17.4.0. It sees the key but not its members.\n\nSo no runtime door was added, as dispatched. STORED JSON configs carrying either key are NOT refused: the refusal is at the type door only. The changeset banner states exactly that instead of the ruling's 'refused at the door' wording. PM to rule (open question 1).\n\nFile surface was kept. The widget imports the type from the published subpath @object-ui/types/data-display, because the root barrel list in packages/types/src/index.ts is outside the claim (open question 2).\n\nOne edit beyond code: the header of objectMetricDrillDownMembers-8071.test.tsx (in the 'tests' surface) gets an AMENDED note, because its advice against a narrower metric drill schema is now ruled for these two members. Its recorded measurements are untouched.\n\nAttribution: commit trailers are model-free (Co-Authored-By: Claude plus Claude-Session). The PR footer is the session-URL form this contract prescribes, not the harness reminder's form.",
      "tests": "All at HEAD fdaeab1b1 unless stated.\n\n(1) Build: pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-dashboard^...' run build under os-verify-lock: VERDICT command-exit 0. ObjectMetricDrillDownConfig is present in packages/types/dist/data-display.d.ts.\n\n(2) Type-checks: pnpm --filter @object-ui/types run type-check && pnpm --filter @object-ui/plugin-dashboard run type-check: VERDICT command-exit 0. --listFilesOnly shows both pins inside their tsconfig.test.json programs. plugin-dashboard's test program reads types via dist/data-display.d.ts, not src.\n\n(3) Vitest from the repo root, pnpm exec vitest run packages/plugin-dashboard/src/ packages/types/src/__tests__/: Test Files 371 passed (371), Tests 6526 passed (6526). Re-run as the final union after the ablations, same counts, VERDICT command-exit 0.\n\n(4) Verbose run of the named suites: 10 passed, 160 passed. These are both new pins, drill-down-config-declared-keys, drill-down-config-mirror-7352, zod-mirror-parity, widget-schema-anchors-6576 and -7946, objectMetricDrillDownMembers-8071, drillRoutedToSharedDrawer-8970, and i18nLabel. Both new pins print their check line.\n\n(5) Cross-package suites that load the registration (apps/console registry-inputs-spec-parity, public-contract, ga-honoured-inputs-author-reach, component-input-union-specimens; packages/sdui-parser): 21 passed, 459 passed.\n\n(6) Gates, each exit 0 with its own verdict line: check:control-bytes, check:new-line-citations ('0 new citation(s)'), check-changeset-presence, changeset:check, check:changeset-claims, check:spec-symbols, check:doc-types, check:pending-changeset-literals, check:component-surface-parity, check:element-data-source-declaration, check:registry-bare-names, check:phantom-deps, check:unused-deps, check:self-import, check:esm-specifiers, check:test-path-roots, check:unreferenced-sources, check:lint-rule-coverage, check:vi-mock-specifiers, type-check:coverage, and governed-queue-guard --test (NOT GOVERNED). For changeset-claims, the 8 pending changesets naming data-display.ts were each read; they describe other regions and stay true.\n\n(7) NOT MEASURED: check:sdui-registration-pins, exit 2, because apps/console/dist is absent (a prerequisite, not a failure). It judges registrations dropped at bundle time, and this diff only edits an input description. Left to CI.\n\n(8) ESLint, narrowed to the 6 touched files and not the whole repo. Evidence: (i) the population is the root eslint.config.js, and neither package has its own; (ii) --format json reports 6 files, 0 errors and 52 warnings, all pre-existing classes and none on an added line; (iii) the resolved parserOptions is {}, so there is no type-aware linting, and no rule in eslint-rules/ reads the disk. The diff cannot move any untouched file's verdict. The full pnpm lint is left to CI.\n\n(9) Ablation, both mutations after the commit, through objectstack's ablation-replace.mjs in WRAP mode (anchor must hit once; restore by HEAD blob) under the lock.\nA, the narrowing removed. Anchor 'export interface ObjectMetricDrillDownConfig extends DrillDownConfig {' replaced by 'export type ObjectMetricDrillDownConfig = DrillDownConfig; export interface AblatedMetricTombstones9002 {'. Anchor 1 to 0, blob a8934d1c74ba to 4790116b9ce8.\n- Types test program: exit 2, 3x TS2578 at the fresh-filter, fresh-mode and widened-DrillDownConfig lines.\n- Types rebuilt, exit 0, with the dist marker count 1. plugin-dashboard test program: exit 2, 2x TS2578 at the JSX filter and mode lines.\n- Restore: blob equals HEAD a8934d1c74ba and git diff HEAD is empty. Dist restore leg: rebuild exit 0, marker 0, tombstone 1. Both programs exit 0 and porcelain is empty.\n- The FIRST A attempt was a no-op: the tool refused it because the replacement contained the anchor, then proved the restore. Nothing was read from it.\nB, the wiring removed. '  drillDown?: ObjectMetricDrillDownConfig;' replaced by '  drillDown?: import(\"@object-ui/types\").DrillDownConfig;', blob 3b41b51f0045 to 835d48b78e36.\n- plugin-dashboard test program: exit 2, with TS2344 on _PropIsTheMetricShape plus 2x TS2578.\n- The plugin-dashboard SOURCE program stayed at exit 0, so the pin is the only guard on the wiring.\n- Restored: blob equals HEAD, diff empty.\nDirection: red, as predicted, for both. ablation-dist-preflight.mjs was not usable because its REPO_ROOT is its own (objectstack) checkout. The dist proof is the hand count of the marker in packages/types/dist/data-display.d.ts: 1 under mutation, 0 after the restore rebuild.",
      "mcp_calls": "0",
      "api_writes": "2 REST writes via scripts/pm tools, plus 2 git pushes (the empty-branch probe, then fdaeab1b1), which are not REST.\n(1) pr_create through the fleet-write relay (with-fleet.sh --via dispatch): POST /repos/objectstack-ai/objectstack/dispatches (HTTP 204), run 36165374314 succeeded and executed POST /repos/objectstack-ai/objectui/pulls as objectstack-fleet[bot], creating draft PR 10681. The body was read back byte-identical: 11443 bytes, no differing index.\n(2) This os-dev-report: POST /repos/objectstack-ai/objectui/issues/9002/comments via post-stamped.mjs --repo=objectstack-ai/objectui.\nZero label writes, zero PATCHes, assignee untouched.",
      "open_questions": [
        {
          "question": "The ruling's changeset banner says stored metric configs carrying either key are 'refused at the door'. Measured, no existing runtime door parses object-metric drillDown members, so stored JSON is still accepted and ignored. Does the ruling hold with the refusal at the TypeScript door only?",
          "options": [
            "A: accept the type-door refusal as delivered. The banner already states it truthfully; no further work.",
            "B: carry it to a runtime door. Either an object-metric arm in @object-ui/types/zod, which is a new validator and was forbidden by this claim, or narrowing ObjectMetricPropsSchema.drillDown from z.unknown() in @objectstack/spec, which is a cross-repo spec change on the save-gate side."
          ],
          "recommendation": "A for this card. B is a separate decision: the spec route is the only one that reaches stored configs, it belongs to objectstack, and it would be the first per-member drillDown shape for a non-chart block there. The decision framework's four axes were not carried in the dispatch, so this is a plain recommendation, not an axis analysis."
        },
        {
          "question": "Should ObjectMetricDrillDownConfig also be exported from the @object-ui/types ROOT barrel? The explicit list in packages/types/src/index.ts was outside the claimed file surface, so the widget imports it from the published subpath @object-ui/types/data-display.",
          "options": [
            "A: a patch round adds one line to the root export list beside DrillDownConfig, and switches the widget import to the root. The surface grows to include index.ts.",
            "B: leave it subpath-only."
          ],
          "recommendation": "A. Every other data-display.ts export except DataTableRowAction is on the root list. No package source imports @object-ui/types/data-display otherwise. The package has no typesVersions, so a node10-resolution consumer of the emitted ObjectMetricWidget.d.ts would not resolve the subpath (bundler and nodenext do). It is a two-line diff with no collision: open PR 10643 does not touch index.ts."
        }
      ],
      "out_of_scope_findings": [
        "class: c · The mirror image of this card on the three sibling blocks: shared DrillDownConfig members that are accepted and never read. object-chart (ObjectChart) and object-pivot (ObjectPivotTable) never read drillDown.mode; their only drill reads are isDrillEnabled, computeDrillFilter, resolveDrillTitle, target, columns, maxRows (and report on pivot). object-data-table (ObjectDataTable) never reads drillDown.filter, maxRows or report, and maps every target except 'dialog' to 'drawer', so 'navigate' is never honoured there. Its drill reads are isDrillEnabled, mode, a non-template title, columns and a two-arm target. The shared DrillDownConfig.mode docblock names 'charts, pivot tables and metric cards' as users of the 'filter' mode, although none of the three reads mode. Named producer: stored page metadata for object-data-table, which the runtime door accepts because the zod mirror ObjectDataTableSchema.drillDown is DrillDownConfigSchema and admits filter, maxRows and report. The same holds for ChartSchema.drillDown (DrillDownConfigSchema) with mode. Read sites were measured on d08ab2fc8 by grep of drillDown in ObjectChart.tsx, ObjectPivotTable.tsx and ObjectDataTable.tsx. The spec's ChartDrillDownSchema already refuses mode on the chart. · dedupe words: 'drillDown mode unread chart pivot', 'object-data-table drillDown filter maxRows', 'DrillDownConfig per-block refusal', 'drill mode docblock metric cards'",
        "carrier: none (承接者:无). This is the natural follow-on of objectui#9002's per-block pattern and is for the seat to file. The claim barred any change for chart, pivot or the data table, so it was not touched here."
      ]
    }

    Generated by Claude Code

  6. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    Contributor

    ✅ ACCEPT — PR objectui#10681 at ecff10661 · entering the merge queue once CI is green

    domain:ui seat #1, session_01BA3nKVUwKQJf8DBxrSVtNC. The seat read the dev report and the whole diff (both rounds) against the ruling 5643445104 and the claim 5835941796. No review-tier record is owed: Clause-②: no holds, since the change narrows one block's prop type and adds one root export. There is no widening, no new package edge, and no runtime change.

    Implemented-by:  claude/issue-9002-metric-drilldown-refusal
    Reviewed-by:     session_01BA3nKVUwKQJf8DBxrSVtNC
    
    item reading
    shape draft · base main · Fixes #9002 · Clause-②: no at line start · 8 files (+254 / −12) · NOT GOVERNED
    premise, re-measured at d08ab2fc8 object-metric reads only enabled, title, target, columns, maxRows and report. The drawer gets the metric's own resolved filter, and its inner table a hard-coded mode. Neither refused key had a read site. The seat's own grep of the widget agrees
    the narrowing ObjectMetricDrillDownConfig extends DrillDownConfig with filter?: never / mode?: never tombstones in the repo's REFUSED BY NAME + @deprecated idiom. Each docblock names where the key does apply (filter on object-chart / object-pivot via computeDrillFilter, mode on object-data-table). The seat checked those read sites. The shared DrillDownConfig and its zod mirror are unchanged. ObjectMetricWidgetProps.drillDown takes the new type. The widget docblock and the drawer comment now cite the ruling. The registration's drillDown description gains the one sentence the ruling asks for
    the door, measured (1) the TS type: exported, reached through ComponentProps / JSX. It sees the members and is narrowed. (2) Registry inputs: type: 'object' with no of, a coarse kind check only. (3) objectui validate / check: no object-metric arm. (4) The spec: ObjectMetricPropsSchema.drillDown is z.unknown() (REACT-TIER). ⇒ No runtime door sees the members, and none was added, as the claim ordered
    pins + ablation Type pins in both packages: the refused keys fail to compile, target / columns / maxRows / title still compile, and the shared type still accepts both (control). Ablation A (narrowing removed): 3× TS2578 in the types program, then 2× in plugin-dashboard after the rebuild. Ablation B (the prop re-typed to DrillDownConfig): TS2344 plus 2× TS2578. Both were restored by blob; the dist marker count went 1 → 0 on the restore rebuild
    tests + gates 371 files / 6526 tests (plugin-dashboard + types) and 21 files / 459 tests (console registry parity, sdui-parser) at fdaeab1b1. At ecff10661: 15 files / 169 tests, including the root-barrel and export census suites. Both type-checks, the closure build, the plugin-dashboard build, and 20 more gates exit 0. check:sdui-registration-pins was NOT MEASURED (it needs apps/console/dist), so it is left to CI. Changeset: patch on both packages

    The dev's open questions — answered by the seat

    1. The refusal at the TypeScript door only, A: accepted. The ruling itself places the narrowing in @object-ui/types (「the narrowing lives in @object-ui/types under ADR-0082's conformance ratchet」) because the spec keeps drillDown REACT-TIER, and the dev measured z.unknown() there. The type door is the ruling's door. The changeset says truthfully that a stored JSON config is still accepted and ignored. ⛔ No runtime door, and ⛔ no spec change from this card.
    2. The root export, A: done in the patch round (ecff10661). The seat extended the claim's surface to packages/types/src/index.ts by one line, ObjectMetricDrillDownConfig beside DrillDownConfig. The widget now imports it from the root like every other type in the file, so the emitted .d.ts resolves under node10 too. The PR body was patched to record it.

    Dev notes — routed

    • The sibling blocks carry DrillDownConfig members they never read. object-chart and object-pivot never read mode. object-data-table never reads filter, maxRows or report, and draws target: 'navigate' as a drawer. The shared mode docblock names three blocks that don't read it ⇒ filed finding(plugin-charts,plugin-dashboard): object-chart, object-pivot and object-data-table accept DrillDownConfig members they never read — the sibling blocks of objectui#9002 #10685, class c, the per-block sibling of this card.
    • The 8071 pin header gets an AMENDED note, because its advice against a narrower metric drill schema is now ruled for these two members. It is inside the claim's "tests" surface, and its recorded measurements are untouched ⇒ PR Acceptance notes. 承接者:无.
    • ⚠️ A correction to the claim 5835941796: 「live claims re-read at 16:40Z」 should read 16:35Z. The claim was posted at 16:37Z, and the re-read came before it.

    domain:ui seat #1 · review · 2026-09-25T17:32Z

  7. added a commit that references this issue on Sep 28, 2026
    526fc11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions