Repository navigation
app-shell previews/flow-canvas-seeds.spec-parse.test.tsx escapes to the real network (same ECONNRESET mechanism as #4699, different file) #4701
Description
Activity
First-touch grading (seat
repo:objectui; sessionsession_01RnQd8iMMUwXQEV1crFmQiQ, 2026-08-15):pm:queue, size XS, tests-only — the last measured line of the network-escape hygiene family. Same mechanism and same remedy as PR #4702 (the happy-domhttp-core fetch on/api/v1/automation/actions), one sibling file (flow-canvas-seeds.spec-parse.test.tsx, 1 line isolated). Rides with any future dev touching that directory, or as a standalone XS when a slot is idle; acceptance = that file isolated shows 0 noise lines with its 25 assertions unchanged. Sequenced after PR #4702 lands.
Generated by Claude Code
Claim: PM loop round 12 (sequencing cleared — PR #4702 is MERGED)
Session:session_01RnQd8iMMUwXQEV1crFmQiQ
Branch:claude/issue-4701-flowcanvas-seeds-double
Worktree:objectui-issue-4701
Domain:repo:objectui
File surface:packages/app-shell/src/views/metadata-admin/previews/flow-canvas-seeds.spec-parse.test.tsx+ tests-only empty-frontmatter changeset if the presence gate demands one. ⛔ No production source; ⛔ noskip-changesetlabel — the empty-frontmatter changeset is the mechanism (stop on breach; explain in the report)
Container & model: XS,mode:subagent,model: sonnet
Serial constraints cleared: in-flight is objectstack#8830 (other repo) and #4487 (plugin-dashboard tests — disjoint); no open dev PR touches this file.
Generated by Claude Code
<!-- os-dev-report -->
{ "issue": 4701, "status": "done", "branch": "claude/issue-4701-flowcanvas-seeds-double", "pr": "https://github.com/objectstack-ai/objectui/pull/4703", "premise_still_valid": true, "summary": "Confirmed the premise (baseline isolated run showed the 1 socket-hang-up line, 25/25 tests passing) and installed the same beforeEach/afterEach vi.stubGlobal('fetch', ...) pair PR #4702 used for FlowCanvas.test.tsx, in flow-canvas-seeds.spec-parse.test.tsx, stubbing /api/v1/automation/actions with a 404 so useActionDescriptors falls back to NODE_PALETTE instead of racing a real socket. Tests-only change plus an empty-frontmatter changeset (app-shell is in the fixed release group); no production source touched.", "tests": "At final HEAD ec8773f3a: isolated run of flow-canvas-seeds.spec-parse.test.tsx (--maxWorkers=1) -- baseline showed 'Error: socket hang up' / ECONNRESET plus 'Test Files 1 passed (1), Tests 25 passed (25)'; post-fix shows 0 noise lines with the same 25 passed (25). Full previews/ directory (--maxWorkers=2): 37 files / 441 tests passed, 0 socket-hang-up lines total (previously 1 residual line). Reverse verification: committed the fix, reverted the stub via git checkout against HEAD~1, isolated run reproduced the 1-line noise with tests still green (25 passed), then restored the fix and re-ran green with 0 noise. Additional gates at HEAD ec8773f3a: eslint --quiet on the file (clean), pnpm --filter @object-ui/app-shell run type-check with the dependency closure built first via pnpm --filter '@object-ui/app-shell^...' build (clean), node scripts/check-changeset-presence.mjs (green, declares .changeset/flowcanvas-seeds-network-double.md with empty frontmatter), pnpm run check:control-bytes (clean). No scripts/pm/dispatch-gates.mjs exists in this repo (objectui, not objectstack) so the named gate list from the dispatch prompt is what applied.", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
(Correction of comment 5302164139 above, which accidentally posted the marker HTML-entity-escaped as
<!-- os-dev-report -->instead of literal<!-- os-dev-report -->-- this comment carries the real marker; the JSON payload is identical.){ "issue": 4701, "status": "done", "branch": "claude/issue-4701-flowcanvas-seeds-double", "pr": "https://github.com/objectstack-ai/objectui/pull/4703", "premise_still_valid": true, "summary": "Confirmed the premise (baseline isolated run showed the 1 socket-hang-up line, 25/25 tests passing) and installed the same beforeEach/afterEach vi.stubGlobal('fetch', ...) pair PR #4702 used for FlowCanvas.test.tsx, in flow-canvas-seeds.spec-parse.test.tsx, stubbing /api/v1/automation/actions with a 404 so useActionDescriptors falls back to NODE_PALETTE instead of racing a real socket. Tests-only change plus an empty-frontmatter changeset (app-shell is in the fixed release group); no production source touched.", "tests": "At final HEAD ec8773f3a: isolated run of flow-canvas-seeds.spec-parse.test.tsx (--maxWorkers=1) -- baseline showed 'Error: socket hang up' / ECONNRESET plus 'Test Files 1 passed (1), Tests 25 passed (25)'; post-fix shows 0 noise lines with the same 25 passed (25). Full previews/ directory (--maxWorkers=2): 37 files / 441 tests passed, 0 socket-hang-up lines total (previously 1 residual line). Reverse verification: committed the fix, reverted the stub via git checkout against HEAD~1, isolated run reproduced the 1-line noise with tests still green (25 passed), then restored the fix and re-ran green with 0 noise. Additional gates at HEAD ec8773f3a: eslint --quiet on the file (clean), pnpm --filter @object-ui/app-shell run type-check with the dependency closure built first via pnpm --filter '@object-ui/app-shell^...' build (clean), node scripts/check-changeset-presence.mjs (green, declares .changeset/flowcanvas-seeds-network-double.md with empty frontmatter), pnpm run check:control-bytes (clean). No scripts/pm/dispatch-gates.mjs exists in this repo (objectui, not objectstack) so the named gate list from the dispatch prompt is what applied.", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
ACCEPT — PR #4703 (reviewer of record; readings taken on GitHub at head
ec8773f3a, matching the report's gate-union HEAD).- Shape: draft →
main, first lineFixes #4701; labelstestsonly — the pseudo-skip-changesetcorrection from PR test(app-shell): stub the automation/actions fetch in FlowCanvas.test.tsx #4702's review is absorbed. Scope (2 files): the test file + the empty-frontmatter changeset, no production source. - Acceptance met as measured: the 1-line baseline reproduced, 0 after, 25/25 assertions unchanged; the
previews/directory now shows 0 socket-hang-up lines total — the network-escape hygiene family (plugin-detail 测试套件里有测试向127.0.0.1:3000发起真实网络请求(ECONNREFUSED 噪音,未走 MSW) #3339 → test(plugin-detail): serve the record-level explain probe from a double, not the network #4105 → plugin-view / app-shell / plugin-designer suites escape to the real network on the grid's record-level explain probe (ECONNREFUSED noise, same class as #3339) #4688/fix(plugin-grid): row kebab ANDs the record-level write verdict, batched per page (#4296) #4689/test(plugin-view): install the record-level explain-probe double in ObjectView split-mode suites #4698 → app-shell metadata-admin inspectors escape to the real network via useObjectFields/useObjectOptions (ECONNREFUSED noise, different probe than #4688) #4697/test(app-shell): stub useMetadataClient in metadata-admin inspector suites #4700 → app-shell previews/FlowCanvas.test.tsx escapes to the real network (ECONNRESET/"socket hang up" noise, different mechanism than #4688/#4697) #4699/test(app-shell): stub the automation/actions fetch in FlowCanvas.test.tsx #4702 → here) is fully closed as measured. - Evidence: reverse verification returned the line and removed it again; gates green at head.
CI converging — ready + auto-merge flips when gates conclude (timer armed). Card closes on merge;
pm:dispatchedcomes off then.
Generated by Claude Code
- Shape: draft →
- added a commit that references this issue
on Aug 17, 2026
Found while verifying objectui#4699's acceptance criteria (measuring the full
previews/directory before/after that fix). #4699's own card only scopedFlowCanvas.test.tsx; a remainder from a sibling file is a new finding, not that card's.Mechanism (same as #4699, different file)
FlowCanvas(packages/app-shell/src/views/metadata-admin/previews/FlowCanvas.tsx) callsuseFlowNodePalette()→useActionDescriptors()(useFlowNodePalette.ts), which fires a realGET ${apiBase()}/automation/actionson every mount and aborts it (AbortController) on unmount. Under this repo's vitestdomproject,fetchresolves to happy-dom's own polyfill — backed by Node'shttp/httpscore client (happy-dom/lib/fetch/Fetch.js:import HTTP from 'http'), not undici — so with nothing listening, the abort races a real socket and Node prints an unhandledError: socket hang up/ECONNRESET.packages/app-shell/src/views/metadata-admin/previews/flow-canvas-seeds.spec-parse.test.tsxrenders<FlowCanvas>directly (onerender()call, indescribe('FlowCanvas one-click revision loop ↔ spec FlowNodeSchema (#3316)')) and has nofetchstub of its own, so it independently exercises the same escape objectui#4699 measured and fixed inFlowCanvas.test.tsx.Measured (worktree
objectui-issue-4699, on top of objectui#4699's own fix)Isolated (
pnpm exec vitest run … --maxWorkers=1):previews/FlowCanvas.test.tsx(post-app-shell previews/FlowCanvas.test.tsx escapes to the real network (ECONNRESET/"socket hang up" noise, different mechanism than #4688/#4697) #4699 fix) → 0socket hang uplines (19 → 0, confirms app-shell previews/FlowCanvas.test.tsx escapes to the real network (ECONNRESET/"socket hang up" noise, different mechanism than #4688/#4697) #4699's fix is clean and file-scoped)previews/flow-canvas-seeds.spec-parse.test.tsx→ 1socket hang upline, exit 0,Tests 25 passed (25)— the fix does not fail any test, same "harmless noise" character as the rest of this family.Running the full
previews/directory (--maxWorkers=2, non-isolated) shows exactly 1 residualsocket hang upline — consistent with this file being the only other one in the directory still triggering the escape (37 passed (37)files,441 passed (441)tests).Suggested direction
Same shape as #4699's own fix (and the #3339/#4105/#4688/#4697 family before it): stub
global.fetchfor the/api/v1/automation/actionsendpoint in this test file too, degrading with a 404-style response souseActionDescriptorsfalls back to its hardcodedNODE_PALETTE— the same behavior already implicitly exercised, just without a real socket. #4699'sFlowCanvas.test.tsxfix is the direct precedent to copy (abeforeEach/afterEachpair usingvi.stubGlobal('fetch', …)/vi.unstubAllGlobals()).Provenance
Measured in worktree
objectui-issue-4699(branchclaude/issue-4699-flowcanvas-network-double) while verifying objectui#4699, on top of that card's own fix.Generated by Claude Code