Repository navigation
plugin-dashboard: DatasetWidget.test.tsx escapes to the real network on the dimension-metadata probe (same root cause as #5225) #5280
Description
Activity
- added a commit that references this issue
on Aug 19, 2026 os-support-ai commented
on Aug 19, 2026 CollaboratorAuthorMore actionsTriage (triage seat, session
session_019ZyCHcjXeTFPiS8RWRk4nN, 2026-08-19 round): promoted topm:queue· Bug — a test suite escaping to the real network in shared containers is a live isolation defect (5 real connection attempts per run, results can change with another agent's dev server up), fully measured with reproduction and captured request list.Dispatch-side notes (advisory): fix surface is
packages/plugin-dashboard/src/__tests__/DatasetWidget.test.tsxonly; the fix shape is pre-ruled by the #5225 reference PR (recording double answering the metadata probe, option-free payload, pin the request shape; ⛔ no blanket network stub). Re-measure the "green tests that took the error path" caveat here rather than assuming #5225's result. Serial constraint: confirm #5225's PR state at claim time — same fix pattern, different package, file surfaces disjoint, so parallel is acceptable if the claim comment records it. Size/model suggestion: S-mechanical, sonnet.
Generated by Claude Code
os-support-ai commented
on Aug 19, 2026 CollaboratorAuthorMore actionsClaim: PM loop round 13
Session:session_01RV6yuVCxymHYE16PL9vQkE
Branch:claude/issue-5280-dataset-widget-network-escape
Worktree:objectui-issue-5280
Domain:repo:objectui(plugin-dashboard)
File surface:packages/plugin-dashboard/src/__tests__/DatasetWidget.test.tsxonly (stop on breach; explain in the report)
Container & model: S,mode:subagent,model: sonnet(matching triage's suggestion)
Clause-②: no — test isolation; no shipped behaviour changes.
Serial constraints cleared, both legs triage asked for:- plugin-report suite escapes to the real network on 127.0.0.1:3000 (ECONNREFUSED noise, same class as #3339 / #4106 / #4688) #5225's PR state, confirmed at claim time: PR test(plugin-report): serve the dimension-metadata probe from a double, not the network (#5225) #5283 merged (2026-08-19 ~00:52Z). So the reference implementation is on
main, not in flight — the dev reads the landed fix rather than a branch. Same fix pattern, different package, file surfaces disjoint. packages/plugin-dashboardwas released minutes ago — held all round by the parked PR fix(plugin-dashboard)!: re-key dashboardComponents to the 8 registered schema types #5207 (plugin-dashboard 的dashboardComponents用组件类名作键(全仓唯一一个),README 教的手动注册循环因此注册 11 个没人写的 type、8 个真 type 一个没注册 #5064), which merged at 07:10Z once its changeset was correctedmajor→minorper the maintainer's 2026-08-19 ruling. Sibling plugin-dashboard:ObjectMetricWidgetPropsstill declares the RETIRED{ key, defaultValue }label form — a TS consumer writing the declared shape renders the raw dotted i18n key as the visible label #5264 is dispatched in the same batch intosrc/**(theObjectMetricWidgetPropsmigration) — disjoint from this card's single test file.
⚠️ PR #5207 just re-keyeddashboardComponentsinsrc/index.tsxminutes ago. Mergemainbefore opening the PR.Triage's two ⛔s are carried into the order verbatim: the fix shape is pre-ruled by #5225's landed PR (recording double answering the metadata probe, option-free payload, pin the request shape) — ⛔ no blanket network stub; and re-measure the "green tests that took the error path" caveat here rather than assuming #5225's result. #5225 found all 42 of its pre-existing tests still passed; that was its measurement, and this package's 52 are a different set.
Generated by Claude Code
- plugin-report suite escapes to the real network on 127.0.0.1:3000 (ECONNREFUSED noise, same class as #3339 / #4106 / #4688) #5225's PR state, confirmed at claim time: PR test(plugin-report): serve the dimension-metadata probe from a double, not the network (#5225) #5283 merged (2026-08-19 ~00:52Z). So the reference implementation is on
- added a commit that references this issue
on Aug 19, 2026 os-support-ai commented
on Aug 19, 2026 CollaboratorAuthorMore actions{ "issue": 5280, "status": "done", "branch": "claude/issue-5280-dataset-widget-network-escape", "pr": "https://github.com/objectstack-ai/objectui/pull/5300", "premise_still_valid": true, "summary": "Closed DatasetWidget.test.tsx's real-network escape on the dimension-metadata probe (same useDatasetDimensionMeta root cause as #5225), porting #5225's reference fix shape from PR #5283: a recording double answers /api/v1/meta/object/{name} with an option-free payload, afterEach fails on any non-metadata escape, and cleanup() runs before vi.unstubAllGlobals() in the same afterEach to avoid the LIFO reverse-registration flake #5225 measured. Added 3 pin tests for the probe's own request shape. File surface stayed to DatasetWidget.test.tsx plus a changeset; no product code touched.", "tests": "Baseline at branch point (95cf24168): 52/52 passed, 10 ECONNREFUSED lines (5 real connection attempts: 3x showcase_task, 2x showcase_deal; no invoices request from this file, contra the issue's original capture). After fix, 8 consecutive isolated runs of DatasetWidget.test.tsx: 55/55 passed (52 pre-existing + 3 new pins), 0 ECONNREFUSED every run. Re-confirmed clean (55/55, 0 ECONNREFUSED) at post-merge HEAD 6c4c090e6 after merging origin/main (7260a1ed4, unrelated). Full package run (packages/plugin-dashboard, 64 files/581 tests) also passed. Reverse verification: committed the fix, predicted that checking out the pre-fix origin/main version of the file would restore the 5-attempt/10-line escape and drop the 3 pins (55->52) while the pre-existing 52 stayed green (a swallowed side effect, not a wrong assertion) -- observed exactly that (52/52 passed, 10 ECONNREFUSED), then restored the fix via 'git checkout HEAD -- {path}'. Gates: pnpm --filter '@object-ui/plugin-dashboard' type-check pass; lint pass (0 errors, pre-existing warnings only); node scripts/check-control-bytes.mjs pass; node scripts/check-changeset-presence.mjs pass (empty-frontmatter changeset). scripts/pm/dispatch-gates.mjs does not exist in this repo (objectui, not objectstack) -- ran the dispatch prompt's own named commands instead.", "open_questions": [], "out_of_scope_findings": [ "filed as #5299: DashboardGridLayout.datasetPath.test.tsx has its own real-network escape in packages/plugin-dashboard -- same ECONNREFUSED-on-port-3000 signature, reproduces 3/3 in isolation (1 attempt, 13/13 tests still pass), confirmed independent of DatasetWidget.test.tsx (present/absent with that file removed from the directory); exact fetch call site not yet traced (candidates: the legacy options.data.provider:'object' object-chart path, or the isLegacyRetiredWidget sentinel path -- neither mock result in that file declares `object` on the queryDataset payload, so useDatasetDimensionMeta's own guard should not be the site); likely explains the stray 'invoices' request in #5280's original capture that this PR's fix could not have produced (DatasetWidget.test.tsx has no invoices fixture)." ] }
Generated by Claude Code
- added 4 commits that reference this issue
on Aug 23, 2026
Found while fixing #5225 (plugin-report). Filed unassigned and not fixed there — that card's write surface is
packages/plugin-report, and this is the same defect in a different package.Measured on
origin/main@41f498bcb.The escape
Package-wide,
pnpm exec vitest run packages/plugin-dashboardreports 10 ECONNREFUSED lines over 63 files / 575 tests, and a per-file bisect puts all of them inDatasetWidget.test.tsx:The requests, captured with a
net.Socket.prototype.connectprobe:Root cause — identical to #5225
With no
SchemaRendererProviderin the tree the hook has no hostapiFetchand degrades to the globalfetch— deliberate, documented, and pinned (objectui#4121). Under happy-dom the globalfetchis a real HTTP client, and vitest's happy-dom environment defaults the document URL tohttp://localhost:3000(vitest/dist/chunks/index.DC7d2Pf8.js:url: happyDOM.url || "http://localhost:3000"), so the relative/api/v1/...resolves to a live request. The read is best-effort (catch {}leaves rows as the server sent them), which is why the suite is green while the request always fails.Only the cases whose mocked query result carries
objectreach it — that field is what the hook keys on. The widget's owndataSourcedouble serves the ROWS; the metadata is a second channel that never goes through it, which is why the existing mock does not intercept.Why it is not just noise
A dev server on port 3000 is routine in this repo's shared containers. If one is up those 5 attempts connect — to whatever another agent is running — and the widget's rendered labels change with no line of the test changing.
Also worth checking: a green test that quietly took the error path is not testing what it says. In #5225's plugin-report file all 42 pre-existing tests stayed green once the probe was answered from a double with no option-bearing fields (byte-identical to the failed read), but that has to be re-measured here rather than assumed.
Relationship to the closed family
#4106's title names plugin-charts and plugin-dashboard, but its fix (
ce4b9e8af) landed in fivepackages/plugin-charts/**files only — no plugin-dashboard file was touched. The call site it fixed (ObjectChart's own inline option-color effect) was later extracted into the shareduseDatasetDimensionMetahook by #4389, which is the site above. So this is the #4106 root cause at a consumer that sweep did not cover, not a new one.#5225 (plugin-report) is the same, and its PR is the reference for the fix shape: answer the probe from a recording double that records every URL and fails on any non-metadata route, keep the answer option-free so no pre-existing assertion changes meaning, and pin the previously-unasserted request shape. ⛔ Not a blanket network stub and not an error-swallowing guard.
Recheck
Run vitest from the repo root (objectui#3378).