`@object-ui/providers` declared `@objectstack/spec` but imported it nowhere.
The edge was promoted from `devDependencies` to `dependencies` when
`ThemePreference` was derived from the spec's `ThemeMode` union; objectui#5716
re-pointed that derivation at `@object-ui/types` and removed the last three
import sites, leaving the declaration with no reader.
Re-measured on origin/main at ad0f5f1 with a positive control: the
import-shaped grep returns 0 hits under packages/providers/ and 434 across
packages/ + apps/. The stale `tsconfig.test.json` comment that named the spec
among the specifiers its empty `paths` re-routes is corrected in the same
stroke.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019b5UBNMtTzKbVtZZGvFuxe
Fixes #5753
@object-ui/providersdeclared@objectstack/specindependenciesand imported itnowhere. This drops the declaration and corrects the now-inaccurate prose comment in
packages/providers/tsconfig.test.json, per the unlock comment and the PM dispatch order(
#5753#issuecomment-5396525948) — both of which supersede the body's proposal to deferthis to the spec-pin refresh chain.
Premise re-verification — the whole justification is "zero import sites"
Measured on
origin/mainatad0f5f11f, before removing anything. The card's originalmeasurement was taken on a branch that has since merged, so it had to be re-taken.
The instrument — import-shaped only (
from/require(/import(/vi.mock(/jest.mock(), matching the bare name and every subpath (/ui,/data, …), and coveringtype-only imports because
import type … from '…'matches the same anchor:packages/providers/packages/+apps/(positive control, same command)An empty grep is not a reading on its own. The identical invocation returning 434 hits one
directory level up proves the instrument works and the zero is a real absence. Two narrower
controls agree:
@objectstack/spec/dataimport sites acrosspackages/+apps/= 90, anda plain substring
objectstack/specacross the same trees = 2381.Beyond
src/, checked and clear: both test files,tsconfig.json,tsconfig.test.json,side-effect imports (bare
import '…'), triple-slash reference-types directives,declare module, and tsconfigtypesarrays.packages/providershas novitest.config.tsor build config of its own (
buildis baretsc). Every remaining mention of the string inthe package:
package.json:34— the declaration, removed here.tsconfig.test.json:13— prose, corrected here.CHANGELOG.md×4 — immutable release history, deliberately untouched.The only imports left in the package are
react,@object-ui/types, relative paths, andvitest/@testing-library/reactin tests.check-phantom-dependencies.mjsdoes and does not prove hereThe card flagged that this gate guards the inverse direction — import without a
declaration — and that is correct in one important sense: it never could have reddened on
the dead edge, and its green does not validate that the dependency was unused. A
declared-but-unimported dependency is invisible to it by construction, which is exactly why
this defect needed a human-filed finding rather than a gate.
In the other direction it is load-bearing, and worth stating precisely because it covers a
gap that
type-checkdoes not: after the declaration is gone, any surviving import sitebecomes a phantom dependency, which is what this gate is built to catch.
That distinction matters here because
type-checkalone is not proof of absence. Theroot
package.jsondeclares@objectstack/spec(line 89), so pnpm places it in theworkspace-root
node_modules, and Node's/TypeScript's upward walk reaches it from anypackage directory. Measured after
pnpm installwith the declaration removed:So a stray spec import in this package would still typecheck and still build green. This is
the trap
check-phantom-dependencies.mjs's own header documents (objectui#4394): "adependency-direction check performed BY RESOLUTION returns the wrong answer, and returns it
confidently." The grep above and the phantom-deps gate are the two readings that actually
bear weight; the green
type-checkis corroboration, not proof.Gates — verdict lines as each gate printed them
Run at
89c03822c(the final commit; working tree clean). Exit codes captured before anypipe.
pnpm installDone in 17.2s using pnpm v10.31.0— resolves cleanly with the entry gone; lockfile diff is exactly the one removed importer entrypnpm --filter '@object-ui/providers^...' build@object-ui/types) built first, so the checks below read a fresh.d.tspnpm --filter '@object-ui/providers' run type-checktsc --noEmit && tsc -p tsconfig.test.json— both projects, no outputpnpm --filter '@object-ui/providers' run buildtscpnpm exec vitest run packages/providers/Test Files 2 passed (2)·Tests 7 passed (7)pnpm --filter '@object-ui/providers' run lint✖ 15 problems (0 errors, 15 warnings)— all pre-existing insrc/, which this PR does not touchnode scripts/check-phantom-dependencies.mjs✅ Every in-scope import is declared by the package that publishes it.node scripts/check-changeset-presence.mjs✅ No source of a released package changed in this range, so no changeset is owed.(1 changeset added anyway — see below)node scripts/check-changeset-fixed.mjs✅ All workspace packages are in the changeset fixed group.node scripts/check-changeset-no-major.mjs✅ No changeset declares a major bump.node scripts/check-control-bytes.mjs✅ check-control-bytes: OK (scanned 4990 tracked text file(s); skipped 85 binary).node scripts/check-package-self-import.mjs✅ No package names itself inside its own src/.node scripts/check-lint-coverage.mjs✅ lint coverage: 46/46 packages linted, 0 with outstanding errors (0 total).node scripts/check-type-check-coverage.mjs✅ type-check coverage: 45/46 via type-check … 41/41 packages compile their testsTwo notes on how the suite was run, both deliberate:
pnpm --filter '@object-ui/providers' run test. This repo's ownguard refuses that invocation (
vitest 调用被拒绝, objectui#3378): a package-directoryvitest root silently runs
apps/console's 22 files and reports them as green while runningnone of this package's. Re-run from the repo root as the guard instructs, which is what the
passing
2 files / 7 testsabove reports.node scripts/check-published-dist-tooling.mjswas not run locally — a declarednarrowing. It rebuilds every package and exceeds this container's foreground limit; CI owns
it. It is also unreachable by this diff, which touches no
src/, no build script and notsconfig the build uses (
tsconfig.test.jsonisnoEmit).packages/providers/dist/wasinspected directly and carries no tooling material.
Published surface
Built and inspected:
dist/types.d.tsimports onlyreactand@object-ui/types; noemitted
.d.tsor.jsreferences a spec symbol. The fourobjectstackstrings survivingin
dist/are prose in doc comments (@objectstack/service-storagein an adapter's TSDoc,two issue references) plus one adapter name string literal — no module specifier among them.
Changeset
check-changeset-presence.mjssays none is owed (it scoressrc/changes, and this diff hasnone). Added one anyway, scored
patch, because the honest question is what consumersinstall and that genuinely changes: the published manifest loses a
dependenciesentry.patch, notminor: there is no API or behaviour change, and no supported access goes away.Consumers on an isolated
node_modulesnever had legitimate reach-through to@objectstack/specvia this package — any consumer that did import it was relying on flat-install hoisting, which was never a contract. The install graph is the only thing that moves.
For contrast, the change that added this edge was scored
minorbecause it changed thepublic
.d.ts; nothing in this PR touches a type.Scope
Exactly the two files the card names, plus the changeset and the lockfile line
pnpm installregenerated. No other package's spec declaration is touched — the range question for packages
whose published
d.tsreferences spec-17.1.0-only symbols is #5793's, a separateun-dispatched card.
(Body edited once after creation: GitHub's body sanitizer had eaten two short
angle-bracket fragments — the
TREEplaceholder in the grep block and the triple-slashdirective name. Same content, spelled without angle brackets.)
Generated by Claude Code