You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
resolveSpecDistInjection validates the override's exports targets but not that its own dependencies resolve, so a dep-less spec dist fails ~80s later as a rolldown "failed to resolve zod" #5391
Observation, found while working #5388. Not a regression and not blocking anything — filing so triage can rank it rather than sitting on it.
What I measured
scripts/vite-objectstack-spec-dist.ts states two properties on purpose, and the first one is:
Loud, never lenient. Every way the override can be wrong — path absent, not the spec package, an exports entry naming a file the built package does not contain — throws with the offending value named.
It checks that each exports-map target file exists. It does not check that the overriding package's own runtime dependencies resolve from where the package sits. Pointing OBJECTSTACK_SPEC_DIST at a real, fully built @objectstack/spec copy that has no reachable node_modules produced no error from the helper at all. The console build ran to completion — 8592 modules transformed, ~80 seconds — and then failed with:
Error: [vite]: Rolldown failed to resolve import "zod" from
"/…/framework-spec/packages/spec/dist/index.mjs".
This is most likely unintended because it can break your application at runtime.
Symlinking the package's dependency set next to it made the same build green.
Why it is worth a line
The failure IS loud, so this is not the silent-skew class the hook exists to kill. What it costs is diagnosis: the message names zod and a rolldown resolver, not OBJECTSTACK_SPEC_DIST, and it arrives a build-length after the mistake rather than at the point the override is read. The helper's stated contract is that a wrong override names itself.
One sharp edge found alongside it, which is why the ordering matters: while #5388 was unfixed, this resolve error was completely invisible — the lazy-linter counter-probe threw in generateBundle first and aborted the build before the accumulated resolve errors were escalated. Same command, same tree, two different single-error reports depending on which failure got there first.
Scope note
scripts/build-console.sh in the framework points the override at an installed tree, where deps resolve, so this is not reachable from the path that matters today. It is reachable by hand and by any future caller that builds a spec package in isolation.
Possible shapes (not a recommendation)
Resolve one known dependency of the override from packageDir in findSpecPackageDir and fail with the override value named.
Or leave it and document the failure mode in the module header, since the build does stop either way.
Triage (label hygiene only): removed the leftover finding label — the card already carries pm:queue + domain:devx, i.e. it is graded and dispatchable, and finding means "awaiting first grading". Dual-state cards are invisible-or-double-counted in both views; no other change. This comment comes from the triage seat Routine, session session_01LyffLrbaFXSRuGRbpb1y5X.
Claim: PM loop round 8
Session: session_019b5UBNMtTzKbVtZZGvFuxe
Branch: claude/issue-5391-spec-dist-dep-validation
Worktree: objectui-issue-5391
Domain: domain:devx (@ objectui, seat #5748)
File surface: scripts/vite-objectstack-spec-dist.ts (+ its test if one exists / you add one)
Container & model: S–M, mode:subagent, model: sonnet
Clause-②: no
Serial constraints cleared: in-flight 0 at round open. Co-dispatched: #5174 final batch (content/docs/** + doc-snippet ledger), #5007 (apps/console/src/__tests__/), #5306 (root package.json), #4902 (scripts/__tests__/scripts-type-check.test.ts) — all disjoint. ⚠️ Note #4926 landed today and changed tsconfig.scripts.json, the program that compiles your file; base off a main containing d8b48f495.
The card
resolveSpecDistInjection validates that the override's exports targets resolve, but not that its own dependencies do — so a dep-less spec dist passes validation and then fails ~80 seconds later as a rolldown failed to resolve zod, at a point that names neither the override nor the real cause.
This is a fail-fast card: same failure, moved from the far end of a build to the validation step that exists to catch it, with a message that names the override.
Zone 2 — measure before writing
⚠️Reproduce the late failure first. The card's value is the distance between cause and symptom; if you cannot produce the ~80s rolldown error, say so and report what you got instead. ⛔ Do not implement a check for a failure you never saw.
Establish what "its own dependencies resolve" should mean here — the dist's package.jsondependencies present in the resolved tree? importable? The card names zod as the observed case. ⛔ Do not over-generalise into a full dependency-graph validator; the card is about the override's own declared deps.
The error message is the deliverable as much as the check: it must name the override and the unresolvable dependency. A fail-fast that says "validation failed" reproduces the original problem one step earlier.
⛔ If the validation cannot be done cheaply at that point (e.g. it requires a resolve pass that costs as much as the build), stop and report — a slow validator on every build is a worse trade than a late error, and that is a real possible outcome.
Gates
No dispatch-gates.mjs here — derive from your diff. At minimum pnpm type-check:scripts, the scripts/__tests__ suite, Lint, and an actual build exercising the injection path. Run check-changeset-presence.mjs and follow its verdict; ⛔ no skip-changeset label (#4912/#3724).
⚠️Restore idiom (objectstack#11648): git checkout <ref> -- <path> writes the index, so a trap restoring with bare git checkout -- <path> reads back the mutation and exits 0. Use git checkout HEAD -- <path>; prove it with git diff HEAD.
{
"issue": 5391,
"status": "done",
"branch": "claude/issue-5391-spec-dist-dep-validation",
"pr": "https://github.com/objectstack-ai/objectui/pull/5995",
"premise_still_valid": true,
"summary": "resolveSpecDistInjection now validates the override's own package.json dependencies resolve from packageDir (via a manual ancestor node_modules walk, not require.resolve -- see tests below), failing loudly at config-load time and naming both the override and every unresolved dependency, before any build work happens. Reproduced the validation gap with a real dep-less @objectstack/spec copy injected into a real apps/console vite build: the late failure was NOT the hard 'Rolldown failed to resolve zod' error the issue describes -- current toolchain (vite 8.2.1 + rolldown 1.2.3) silently externalizes the unresolved zod import with zero warning, and only crashed downstream via an unrelated plugin's ENOENT on the OTHER missing dependency (pg-connection-string); filed as #5996. After the fix the same repro fails in ~1s instead of ~80s-2min, naming OBJECTSTACK_SPEC_DIST, the package.json path, and 'zod, pg-connection-string' explicitly.",
"tests": "pnpm type-check:scripts -- pass (exit 0). vitest run scripts/__tests__/vite-objectstack-spec-dist.test.ts -- 33/33 pass (25 pre-existing + 8 new: throws naming override+dep; names every unresolved dep not just first; passes when dep reachable from packageDir's own node_modules; passes when dep reachable from an ANCESTOR node_modules; ignores peerDependencies by design; inert when dependencies absent; the real installed spec -- which declares zod+pg-connection-string -- passes; and a regression test pinning that a dependency name resolvable elsewhere in the repo (typescript, via require_.resolve) does NOT get treated as resolved from packageDir). eslint on both changed files -- 0 errors (5 pre-existing no-explicit-any warnings elsewhere in the test file, none on added lines). node scripts/check-changeset-presence.mjs -- '0 file(s) ... under the src/ of a package the release covers ... No source of a released package changed in this range, so no changeset is owed' (exit 0). node scripts/check-control-bytes.mjs -- OK. Real apps/console vite build, three configurations, commit 6c7d942ad: (1) unset override (baseline) -- EXIT=0, unaffected, matches pre-change behavior exactly; (2) OBJECTSTACK_SPEC_DIST at a dep-less copy of the installed spec -- BEFORE: ran to '8613 modules transformed' then failed ~80s-2min in with 'error during build: ... [plugin emit-eager-closure-report] Error: ENOENT: no such file or directory, open .../apps/console/dist/pg-connection-string' (no zod warning/error at all -- zod was silently externalized); AFTER: 'real 0m0.918s ... failed to load config from .../vite.config.ts \n error during build: \n Error: OBJECTSTACK_SPEC_DIST: `.../dep-less-spec/package.json` declares dependencies that do not resolve from `.../dep-less-spec`: pg-connection-string, zod -- the override points at a spec dist with no reachable `node_modules` for them. Install the override's own dependencies ... before setting `OBJECTSTACK_SPEC_DIST`' (exit 1, ~1s); (3) same fixture with zod+pg-connection-string symlinked into its own node_modules (deps now genuinely reachable) -- EXIT=0, full build succeeds, injection still works end-to-end, proving no false positive on the real injection path.",
"open_questions": [],
"out_of_scope_findings": [
"filed as #5996: emit-eager-closure-report (apps/console/vite.config.ts) crashes with a bare ENOENT, several frames from the real cause, when a fully-unresolvable dependency lands in the vendor-objectstack chunk as a written-but-empty chunk entry -- found while reproducing this issue's late failure, no longer reachable via OBJECTSTACK_SPEC_DIST after this fix but reachable via any other future unresolvable eager-closure member"
]
}
os-dev-report (previous comment's HTML marker was stripped by the sanitizer; reposting with a literal marker per protocol)
{
"issue": 5391,
"status": "done",
"branch": "claude/issue-5391-spec-dist-dep-validation",
"pr": "https://github.com/objectstack-ai/objectui/pull/5995",
"premise_still_valid": true,
"summary": "resolveSpecDistInjection now validates the override's own package.json dependencies resolve from packageDir (via a manual ancestor node_modules walk, not require.resolve -- see tests below), failing loudly at config-load time and naming both the override and every unresolved dependency, before any build work happens. Reproduced the validation gap with a real dep-less @objectstack/spec copy injected into a real apps/console vite build: the late failure was NOT the hard 'Rolldown failed to resolve zod' error the issue describes -- current toolchain (vite 8.2.1 + rolldown 1.2.3) silently externalizes the unresolved zod import with zero warning, and only crashed downstream via an unrelated plugin's ENOENT on the OTHER missing dependency (pg-connection-string); filed as #5996. After the fix the same repro fails in ~1s instead of ~80s-2min, naming OBJECTSTACK_SPEC_DIST, the package.json path, and 'zod, pg-connection-string' explicitly.",
"tests": "pnpm type-check:scripts -- pass (exit 0). vitest run scripts/__tests__/vite-objectstack-spec-dist.test.ts -- 33/33 pass (25 pre-existing + 8 new: throws naming override+dep; names every unresolved dep not just first; passes when dep reachable from packageDir's own node_modules; passes when dep reachable from an ANCESTOR node_modules; ignores peerDependencies by design; inert when dependencies absent; the real installed spec -- which declares zod+pg-connection-string -- passes; and a regression test pinning that a dependency name resolvable elsewhere in the repo (typescript, via require_.resolve) does NOT get treated as resolved from packageDir). eslint on both changed files -- 0 errors (5 pre-existing no-explicit-any warnings elsewhere in the test file, none on added lines). node scripts/check-changeset-presence.mjs -- '0 file(s) ... under the src/ of a package the release covers ... No source of a released package changed in this range, so no changeset is owed' (exit 0). node scripts/check-control-bytes.mjs -- OK. Real apps/console vite build, three configurations, commit 6c7d942ad: (1) unset override (baseline) -- EXIT=0, unaffected, matches pre-change behavior exactly; (2) OBJECTSTACK_SPEC_DIST at a dep-less copy of the installed spec -- BEFORE: ran to '8613 modules transformed' then failed ~80s-2min in with 'error during build: ... [plugin emit-eager-closure-report] Error: ENOENT: no such file or directory, open .../apps/console/dist/pg-connection-string' (no zod warning/error at all -- zod was silently externalized); AFTER: 'real 0m0.918s ... failed to load config from .../vite.config.ts \n error during build: \n Error: OBJECTSTACK_SPEC_DIST: `.../dep-less-spec/package.json` declares dependencies that do not resolve from `.../dep-less-spec`: pg-connection-string, zod -- the override points at a spec dist with no reachable `node_modules` for them. Install the override's own dependencies ... before setting `OBJECTSTACK_SPEC_DIST`' (exit 1, ~1s); (3) same fixture with zod+pg-connection-string symlinked into its own node_modules (deps now genuinely reachable) -- EXIT=0, full build succeeds, injection still works end-to-end, proving no false positive on the real injection path.",
"open_questions": [],
"out_of_scope_findings": [
"filed as #5996: emit-eager-closure-report (apps/console/vite.config.ts) crashes with a bare ENOENT, several frames from the real cause, when a fully-unresolvable dependency lands in the vendor-objectstack chunk as a written-but-empty chunk entry -- found while reproducing this issue's late failure, no longer reachable via OBJECTSTACK_SPEC_DIST after this fix but reachable via any other future unresolvable eager-closure member"
]
}
Reviewer of record: domain:devx @ objectui seat (#5748), round R8, PM session session_019b5UBNMtTzKbVtZZGvFuxe. Verified against the branch — ⛔ not against the report. Scope: 2 files, +262/−1.
⚠️ The card's symptom was falsified, and reality is worse
The card said the dep-less override fails ~80s later as a rolldown failed to resolve zod. The dispatch required reproducing that before implementing. It reproduced with a real dep-less spec copy in a real apps/console build — and got something else:
Current toolchain (vite 8.2.1 + rolldown 1.2.3) silently externalizes the unresolved zod import with zero warning. The crash that eventually arrives is an unrelated plugin's bare ENOENT on the other missing dependency, pg-connection-string.
So the real behaviour is not "a confusing error 80 seconds later" but "no error at all for the named dependency, and a crash from a different plugin about a different package." ⛔ A dev that had implemented against the card's description would have shipped a fix for a failure mode that no longer exists, and reported it as verified. Filed onward as #5996.
The design decision that makes this gate real rather than vacuous
The obvious implementation is require.resolve(name, { paths: [packageDir] }). The dev measured that it does not work here and documented why in the code:
apps/console/node_modules/.bin/vite exports NODE_PATH pointing at pnpm's flat .pnpm/node_modules hoist directory … everything ever hoisted lives there, zod included, so require.resolve reported it resolved.
⚠️That is a false negative in the exact environment this validation runs in — inside a vite build launched through the .bin shim. The obvious version would have passed on a dep-less override and reported nothing, which is worse than the bug: a gate that cannot fire, in a file whose whole job is to fire early.
Replaced with a manual ancestor-node_modules directory walk, and pinned by a regression test asserting that a package resolvable elsewhere in the repo (typescript, via require_.resolve) does not count as resolved from packageDir. The trap is guarded, not merely avoided.
The three-configuration build proof
Run against real apps/console builds at 6c7d942ad, not fixtures:
ran to "8613 modules transformed", failed ~80s–2min in with a bare ENOENT
dep-less override, after
real 0m0.918s, exit 1, naming OBJECTSTACK_SPEC_DIST, the package.json path, and pg-connection-string, zod
deps symlinked in (genuinely reachable)
EXIT=0, full build succeeds — injection still works end-to-end
⚠️ That last row is the one that matters most and was not asked for: it proves no false positive on the real injection path. A validation that fails closed on a working override would have been a worse outcome than the original bug, and it is the failure a "make it strict" fix produces by default.
~80s–2min → ~1s, with an error that names the override, the file, and every unresolved dependency rather than the first.
Error message
The dispatch said the message is as much the deliverable as the check. It names the env var, the offending package.json, all unresolved deps, the cause ("no reachable node_modules for them"), and the remedy ("install the override's own dependencies before setting OBJECTSTACK_SPEC_DIST"). ⛔ Not "validation failed".
Tests
33/33 (25 pre-existing + 8 new), covering: throws naming override + dep; names every unresolved dep; passes when reachable from packageDir's own node_modules; passes when reachable from an ancestor; ignores peerDependencies by design; inert when dependencies absent; the real installed spec passes; and the require.resolve regression pin.
Path fork checked against the actual file list: scripts/** is not governed surface. Maintainer's ruling, in-session 2026-08-24, verbatim: 「授权 auto-merge(推荐)」 — every check green, ⛔ not the required subset.
Activity
os-zhuang commentedon Aug 21, 2026
Triage (label hygiene only): removed the leftover
findinglabel — the card already carriespm:queue+domain:devx, i.e. it is graded and dispatchable, andfindingmeans "awaiting first grading". Dual-state cards are invisible-or-double-counted in both views; no other change. This comment comes from the triage seat Routine, sessionsession_01LyffLrbaFXSRuGRbpb1y5X.Generated by Claude Code
yinlianghui-tw commentedon Aug 24, 2026
Claim: PM loop round 8⚠️ Note #4926 landed today and changed
Session:
session_019b5UBNMtTzKbVtZZGvFuxeBranch:
claude/issue-5391-spec-dist-dep-validationWorktree:
objectui-issue-5391Domain:
domain:devx(@ objectui, seat #5748)File surface:
scripts/vite-objectstack-spec-dist.ts(+ its test if one exists / you add one)Container & model: S–M,
mode:subagent,model: sonnetClause-②: no
Serial constraints cleared: in-flight 0 at round open. Co-dispatched: #5174 final batch (
content/docs/**+ doc-snippet ledger), #5007 (apps/console/src/__tests__/), #5306 (rootpackage.json), #4902 (scripts/__tests__/scripts-type-check.test.ts) — all disjoint.tsconfig.scripts.json, the program that compiles your file; base off amaincontainingd8b48f495.The card
resolveSpecDistInjectionvalidates that the override'sexportstargets resolve, but not that its own dependencies do — so a dep-less spec dist passes validation and then fails ~80 seconds later as a rolldownfailed to resolve zod, at a point that names neither the override nor the real cause.This is a fail-fast card: same failure, moved from the far end of a build to the validation step that exists to catch it, with a message that names the override.
Zone 2 — measure before writing
package.jsondependenciespresent in the resolved tree? importable? The card nameszodas the observed case. ⛔ Do not over-generalise into a full dependency-graph validator; the card is about the override's own declared deps.⛔ If the validation cannot be done cheaply at that point (e.g. it requires a resolve pass that costs as much as the build), stop and report — a slow validator on every build is a worse trade than a late error, and that is a real possible outcome.
Gates
No
dispatch-gates.mjshere — derive from your diff. At minimumpnpm type-check:scripts, thescripts/__tests__suite, Lint, and an actual build exercising the injection path. Runcheck-changeset-presence.mjsand follow its verdict; ⛔ noskip-changesetlabel (#4912/#3724).git checkout <ref> -- <path>writes the index, so a trap restoring with baregit checkout -- <path>reads back the mutation and exits 0. Usegit checkout HEAD -- <path>; prove it withgit diff HEAD.Generated by Claude Code
yinlianghui-tw commentedon Aug 24, 2026
{ "issue": 5391, "status": "done", "branch": "claude/issue-5391-spec-dist-dep-validation", "pr": "https://github.com/objectstack-ai/objectui/pull/5995", "premise_still_valid": true, "summary": "resolveSpecDistInjection now validates the override's own package.json dependencies resolve from packageDir (via a manual ancestor node_modules walk, not require.resolve -- see tests below), failing loudly at config-load time and naming both the override and every unresolved dependency, before any build work happens. Reproduced the validation gap with a real dep-less @objectstack/spec copy injected into a real apps/console vite build: the late failure was NOT the hard 'Rolldown failed to resolve zod' error the issue describes -- current toolchain (vite 8.2.1 + rolldown 1.2.3) silently externalizes the unresolved zod import with zero warning, and only crashed downstream via an unrelated plugin's ENOENT on the OTHER missing dependency (pg-connection-string); filed as #5996. After the fix the same repro fails in ~1s instead of ~80s-2min, naming OBJECTSTACK_SPEC_DIST, the package.json path, and 'zod, pg-connection-string' explicitly.", "tests": "pnpm type-check:scripts -- pass (exit 0). vitest run scripts/__tests__/vite-objectstack-spec-dist.test.ts -- 33/33 pass (25 pre-existing + 8 new: throws naming override+dep; names every unresolved dep not just first; passes when dep reachable from packageDir's own node_modules; passes when dep reachable from an ANCESTOR node_modules; ignores peerDependencies by design; inert when dependencies absent; the real installed spec -- which declares zod+pg-connection-string -- passes; and a regression test pinning that a dependency name resolvable elsewhere in the repo (typescript, via require_.resolve) does NOT get treated as resolved from packageDir). eslint on both changed files -- 0 errors (5 pre-existing no-explicit-any warnings elsewhere in the test file, none on added lines). node scripts/check-changeset-presence.mjs -- '0 file(s) ... under the src/ of a package the release covers ... No source of a released package changed in this range, so no changeset is owed' (exit 0). node scripts/check-control-bytes.mjs -- OK. Real apps/console vite build, three configurations, commit 6c7d942ad: (1) unset override (baseline) -- EXIT=0, unaffected, matches pre-change behavior exactly; (2) OBJECTSTACK_SPEC_DIST at a dep-less copy of the installed spec -- BEFORE: ran to '8613 modules transformed' then failed ~80s-2min in with 'error during build: ... [plugin emit-eager-closure-report] Error: ENOENT: no such file or directory, open .../apps/console/dist/pg-connection-string' (no zod warning/error at all -- zod was silently externalized); AFTER: 'real 0m0.918s ... failed to load config from .../vite.config.ts \n error during build: \n Error: OBJECTSTACK_SPEC_DIST: `.../dep-less-spec/package.json` declares dependencies that do not resolve from `.../dep-less-spec`: pg-connection-string, zod -- the override points at a spec dist with no reachable `node_modules` for them. Install the override's own dependencies ... before setting `OBJECTSTACK_SPEC_DIST`' (exit 1, ~1s); (3) same fixture with zod+pg-connection-string symlinked into its own node_modules (deps now genuinely reachable) -- EXIT=0, full build succeeds, injection still works end-to-end, proving no false positive on the real injection path.", "open_questions": [], "out_of_scope_findings": [ "filed as #5996: emit-eager-closure-report (apps/console/vite.config.ts) crashes with a bare ENOENT, several frames from the real cause, when a fully-unresolvable dependency lands in the vendor-objectstack chunk as a written-but-empty chunk entry -- found while reproducing this issue's late failure, no longer reachable via OBJECTSTACK_SPEC_DIST after this fix but reachable via any other future unresolvable eager-closure member" ] }Generated by Claude Code
yinlianghui-tw commentedon Aug 24, 2026
os-dev-report (previous comment's HTML marker was stripped by the sanitizer; reposting with a literal marker per protocol)
{ "issue": 5391, "status": "done", "branch": "claude/issue-5391-spec-dist-dep-validation", "pr": "https://github.com/objectstack-ai/objectui/pull/5995", "premise_still_valid": true, "summary": "resolveSpecDistInjection now validates the override's own package.json dependencies resolve from packageDir (via a manual ancestor node_modules walk, not require.resolve -- see tests below), failing loudly at config-load time and naming both the override and every unresolved dependency, before any build work happens. Reproduced the validation gap with a real dep-less @objectstack/spec copy injected into a real apps/console vite build: the late failure was NOT the hard 'Rolldown failed to resolve zod' error the issue describes -- current toolchain (vite 8.2.1 + rolldown 1.2.3) silently externalizes the unresolved zod import with zero warning, and only crashed downstream via an unrelated plugin's ENOENT on the OTHER missing dependency (pg-connection-string); filed as #5996. After the fix the same repro fails in ~1s instead of ~80s-2min, naming OBJECTSTACK_SPEC_DIST, the package.json path, and 'zod, pg-connection-string' explicitly.", "tests": "pnpm type-check:scripts -- pass (exit 0). vitest run scripts/__tests__/vite-objectstack-spec-dist.test.ts -- 33/33 pass (25 pre-existing + 8 new: throws naming override+dep; names every unresolved dep not just first; passes when dep reachable from packageDir's own node_modules; passes when dep reachable from an ANCESTOR node_modules; ignores peerDependencies by design; inert when dependencies absent; the real installed spec -- which declares zod+pg-connection-string -- passes; and a regression test pinning that a dependency name resolvable elsewhere in the repo (typescript, via require_.resolve) does NOT get treated as resolved from packageDir). eslint on both changed files -- 0 errors (5 pre-existing no-explicit-any warnings elsewhere in the test file, none on added lines). node scripts/check-changeset-presence.mjs -- '0 file(s) ... under the src/ of a package the release covers ... No source of a released package changed in this range, so no changeset is owed' (exit 0). node scripts/check-control-bytes.mjs -- OK. Real apps/console vite build, three configurations, commit 6c7d942ad: (1) unset override (baseline) -- EXIT=0, unaffected, matches pre-change behavior exactly; (2) OBJECTSTACK_SPEC_DIST at a dep-less copy of the installed spec -- BEFORE: ran to '8613 modules transformed' then failed ~80s-2min in with 'error during build: ... [plugin emit-eager-closure-report] Error: ENOENT: no such file or directory, open .../apps/console/dist/pg-connection-string' (no zod warning/error at all -- zod was silently externalized); AFTER: 'real 0m0.918s ... failed to load config from .../vite.config.ts \n error during build: \n Error: OBJECTSTACK_SPEC_DIST: `.../dep-less-spec/package.json` declares dependencies that do not resolve from `.../dep-less-spec`: pg-connection-string, zod -- the override points at a spec dist with no reachable `node_modules` for them. Install the override's own dependencies ... before setting `OBJECTSTACK_SPEC_DIST`' (exit 1, ~1s); (3) same fixture with zod+pg-connection-string symlinked into its own node_modules (deps now genuinely reachable) -- EXIT=0, full build succeeds, injection still works end-to-end, proving no false positive on the real injection path.", "open_questions": [], "out_of_scope_findings": [ "filed as #5996: emit-eager-closure-report (apps/console/vite.config.ts) crashes with a bare ENOENT, several frames from the real cause, when a fully-unresolvable dependency lands in the vendor-objectstack chunk as a written-but-empty chunk entry -- found while reproducing this issue's late failure, no longer reachable via OBJECTSTACK_SPEC_DIST after this fix but reachable via any other future unresolvable eager-closure member" ] }Generated by Claude Code
yinlianghui-tw commentedon Aug 24, 2026
ACCEPT — PR #5995. Landing on CI convergence.
Reviewer of record:
domain:devx@ objectui seat (#5748), round R8, PM sessionsession_019b5UBNMtTzKbVtZZGvFuxe. Verified against the branch — ⛔ not against the report. Scope: 2 files, +262/−1.The card said the dep-less override fails ~80s later as a rolldown
failed to resolve zod. The dispatch required reproducing that before implementing. It reproduced with a real dep-less spec copy in a realapps/consolebuild — and got something else:So the real behaviour is not "a confusing error 80 seconds later" but "no error at all for the named dependency, and a crash from a different plugin about a different package." ⛔ A dev that had implemented against the card's description would have shipped a fix for a failure mode that no longer exists, and reported it as verified. Filed onward as #5996.
The design decision that makes this gate real rather than vacuous
The obvious implementation is
require.resolve(name, { paths: [packageDir] }). The dev measured that it does not work here and documented why in the code:.binshim. The obvious version would have passed on a dep-less override and reported nothing, which is worse than the bug: a gate that cannot fire, in a file whose whole job is to fire early.Replaced with a manual ancestor-
node_modulesdirectory walk, and pinned by a regression test asserting that a package resolvable elsewhere in the repo (typescript, viarequire_.resolve) does not count as resolved frompackageDir. The trap is guarded, not merely avoided.The three-configuration build proof
Run against real
apps/consolebuilds at6c7d942ad, not fixtures:EXIT=0, unaffected — matches pre-change behaviour exactlyENOENTreal 0m0.918s, exit 1, namingOBJECTSTACK_SPEC_DIST, thepackage.jsonpath, andpg-connection-string, zodEXIT=0, full build succeeds — injection still works end-to-end~80s–2min → ~1s, with an error that names the override, the file, and every unresolved dependency rather than the first.
Error message
The dispatch said the message is as much the deliverable as the check. It names the env var, the offending
package.json, all unresolved deps, the cause ("no reachablenode_modulesfor them"), and the remedy ("install the override's own dependencies before settingOBJECTSTACK_SPEC_DIST"). ⛔ Not "validation failed".Tests
33/33 (25 pre-existing + 8 new), covering: throws naming override + dep; names every unresolved dep; passes when reachable from
packageDir's ownnode_modules; passes when reachable from an ancestor; ignorespeerDependenciesby design; inert whendependenciesabsent; the real installed spec passes; and therequire.resolveregression pin.Changeset: none owed — gate run, verdict followed.
Landing
Path fork checked against the actual file list:
scripts/**is not governed surface. Maintainer's ruling, in-session 2026-08-24, verbatim: 「授权 auto-merge(推荐)」 — every check green, ⛔ not therequiredsubset.Generated by Claude Code