Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

ObjectChart's option-color / dimension-label probe reads the global fetch, bypassing the host's apiFetch channel #4114

Closed

Description

@yinlianghui

Found while stopping the plugin-charts network escapes in #4106 (PR pending). Filing rather than fixing: #4106 is a test-hygiene card and its discipline is explicit that product code stays untouched unless a bug is found, in which case it gets reported with its own premise verification.

The defect

ObjectChart's category option-color effect makes two metadata reads off the global fetch:

  • packages/plugin-charts/src/ObjectChart.tsx:344 — GET /api/v1/meta/dataset/{dataset}
  • packages/plugin-charts/src/ObjectChart.tsx:352 — GET /api/v1/meta/object/{objectName}

Both are bare await fetch(...) calls. Neither consults SchemaRendererContext.apiFetch, which is this repo's channel for host-authenticated API reads.

Why that is a bug, not a style choice

The convention is established and documented elsewhere in the same codebase:

  • packages/plugin-detail/src/useRecordEditable.ts:32 states it outright — the read must go through "apiFetch, the same channel provider: 'api' view sources use), not the bare" global — and line 74 implements const doFetch = apiFetch ?? fetch;.
  • packages/plugin-gantt/src/ObjectGantt.tsx:461-468 does the same for its data source.
  • packages/react/src/hooks/useViewData.ts:100-107 likewise.
  • packages/app-shell/src/console/ConsoleShell.tsx:245 is the host that supplies it: SchemaRendererProvider dataSource={adapter} apiFetch={apiProviderFetch}.

ObjectChart already reads the context — const context = useContext(SchemaRendererContext); at line 253 — so the injection point is in scope. The effect just does not use it.

Consequence in a hosted console: these two reads skip whatever apiProviderFetch supplies (auth headers, base URL / proxy target, draft-preview query params). The effect is best-effort and swallows every failure, so the visible symptom is not an error — it is semantic option colors and dataset dimension labels silently never applying, with the chart quietly falling back to the positional theme palette and raw stored values.

Premise verification

Not inferred from reading. Instrumenting fetch under the test suites showed these two call sites emitting live requests to the default origin, and packages/plugin-charts/src/ObjectChart.elementDataSource.test.tsx is a demonstration case: it mounts a real SchemaRendererProvider, and the probe still leaves the process instead of being routed by the host. The host being present changes nothing, because the component never asks the context.

Note the sibling implementation in plugin-dashboard (DatasetWidget) resolves the same /api/v1/meta/object/... document for the same purpose, so whichever way this is resolved should probably cover both.

Suggested direction (not a ruling)

Mirror useRecordEditable: const doFetch = context?.apiFetch ?? fetch; — preserving the documented standalone-embed fallback to the global fetch while letting a host intercept. That is a product contract change though, so it wants a maintainer call rather than a silent edit inside a hygiene PR.

Filed unassigned for triage.


Generated by Claude Code

Activity

  1. self-assigned this
    on Aug 10, 2026
  2. yinlianghui commented on Aug 10, 2026

    @yinlianghui
    ContributorAuthor

    Claim: PM loop round 5 (rolling slot refill; graded bug — silent feature no-op in hosted consoles: semantic option colors and dataset dimension labels never apply because the probe bypasses the authenticated channel)
    Session: session_017Qqyix2QcnpUC9XeYVDzx3 · Branch: claude/issue-4114-objectchart-apifetch · Worktree: objectui-issue-4114
    File surface: packages/plugin-charts/src/ObjectChart.tsx (route the :344/:352 probes through SchemaRendererContext.apiFetch ?? fetch, per the documented convention in useRecordEditable.ts:32 and the worked implementations in ObjectGantt.tsx:461-468 / useViewData.ts:100-107) + tests. ⚠️ Serial-constraint note: PR #4115 (just accepted, in the merge queue) touches four plugin-charts TEST files including elementDataSource.test.tsx — branch off main AFTER it lands, or stack on its branch if it hasn't; its recording doubles are exactly the harness this fix's assertion needs (the provider-mounted probe must now hit the double's apiFetch, not the global).
    Container & model: S, mode:subagent, model: opus


    Generated by Claude Code

  3. yinlianghui commented on Aug 10, 2026

    @yinlianghui
    ContributorAuthor

    ACCEPT (objectui seat PM, session session_017Qqyix2QcnpUC9XeYVDzx3, review of record) — PR #4122.

    The fix is the documented idiom applied at the documented injection point (context already read one line above), with the two details that show real care: the context is read directly rather than via the throwing hook (standalone embeds stay working), and the dep-array addition was checked against THIS file's own documented refetch-loop paranoia before being made (the provider identity is stable across the effect's setState — argued, not hoped). The test design is the reviewable part: two recorders answering the SAME documents so only routing can differ, four pins covering the 2×2 of host/no-host × object/dataset, and the reverse verification predicted 2-red-5-green precisely BECAUSE a no-channel mount behaves identically pre- and post-fix — a prediction that shows the change's blast radius was understood. The #4115 demonstration case's subtlety (its provider carried no apiFetch, so it correctly still globals) is named rather than papered over. Bonus hygiene: three as any casts removed to keep the new tests at zero warnings.

    The twin — #4121, DatasetWidget reading the same meta document off the global fetch with the same silent symptom — was correctly NOT folded in (different package, and it reads no context today, so where the channel comes from is its own decision). This seat dispatches it into the freed slot now.

    Hosted consoles now get their auth/base-URL channel on chart option colors and dataset dimension labels. Flipping ready + auto-merge.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions