Uh oh!
There was an error while loading. Please reload this page.
fix(console,cli): stop printing install instructions for packages nobody can install - #11266
Conversation
…ody can install `@objectstack/framework` is not a real package. Measured against the public npm registry (unauthenticated, with `@objectstack/spec` and `@objectstack/cli` as positive controls) it is 404, and unlike the other out-of-repo names in this tree nothing describes it as enterprise, cloud or private — it is presented as the default *public* install. There is no umbrella package and there never was. The mechanism its README described is real, just misnamed: `@objectstack/cli` declares `@objectstack/console` as a dependency and both ship at one version from the Changesets `fixed` group, so every app that installs the CLI already gets a version-matched Console. The instruction is corrected rather than deleted. `serve`'s multi-org fail-fast told operators to add `@objectstack/organizations` to their app without saying the runtime ships only with an enterprise/cloud subscription — the un-followable "add it to your dependencies" that framework#3366 exists to make legible. The remedy now states it. `@objectstack/security-enterprise` is deliberately untouched: it is a real enterprise package, declared with provenance in PLATFORM_CAPABILITY_PROVIDERS, and its hint already names the edition boundary. The test pinning that hint is strengthened — it now asserts the message carries the roster's edition note verbatim, so the note cannot be stripped while the test stays green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPBxLsqQGCVL5z5UXvgipH
📓 Docs Drift CheckThis PR changes 2 package(s): 16 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 4 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 28 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 5adac686f59476c33480b9b007236ea96fe4f2fe && git checkout 5adac686f59476c33480b9b007236ea96fe4f2fe
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e7d2cc67fdef7fee9d2c6d65d7363fe1c78ce6a4 ce44f60579d424787791077601d4a7f2a1a518fc && git checkout -B drift-repro e7d2cc67fdef7fee9d2c6d65d7363fe1c78ce6a4 && git merge --no-ff ce44f60579d424787791077601d4a7f2a1a518fc
node scripts/docs-audit/affected-docs.mjs --json e7d2cc67fdef7fee9d2c6d65d7363fe1c78ce6a4
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#10921
The measurement was re-taken, and it splits the four names 1 / 3 — not 3 / 1
The ruling of 2026-08-22 made this card's first step a measurement. That measurement was re-run here (unauthenticated
GET https://registry.npmjs.org/@objectstack%2FPKGNAME), and the registry half reproduces exactly:dist-tags.latest@objectstack/framework@objectstack/security-enterprise@objectstack/organizations@objectstack/service-tenant4.1.0@objectstack/spec(positive control)17.1.0@objectstack/cli(positive control)17.1.0What changes is the reading, not the numbers. The dispatching analysis took the three 404s as three fabricated names. Measured against this tree, they are not one population:
@objectstack/framework— fabricated. Nothing in this tree calls it enterprise, cloud, or private. The opposite:packages/console/README.mdpresents it as the default public install (| Use | … | Default install for @objectstack/framework consumers |). There is no umbrella package, and the real public onboarding path —npx create-objectstack, whose template ispackages/create-objectstack/src/templates/blank/package.json— never mentions one.@objectstack/organizationsand@objectstack/security-enterprise— real, and deliberately not public. This tree calls them "closed-source" (serve.ts:2576) and "cloud-private" (serve.ts:229,packages/verify/src/harness.ts:44) in roughly a dozen places, one citingcloud#1013.security-enterpriseis declared with provenance inPLATFORM_CAPABILITY_PROVIDERS(packages/spec/src/kernel/platform-capabilities.ts) asedition: 'enterprise'. Their 404 is the private-package caveat above, not evidence of fabrication.@objectstack/service-tenant— published at 4.1.0, exactly asplatform-object-names.tsdescribes it. Untouched, as instructed.On the A/B fork: a roster already exists, so this adds none
The card's option A was "a declared roster, one row per out-of-repo package, with where it ships". That roster is
PLATFORM_CAPABILITY_PROVIDERSinpackages/spec/src/kernel/platform-capabilities.ts:package+edition(open/enterprise/cloud) + a prosenote, drift-tested 1:1 against the capability vocabulary and read by both the CLI preflight and cloud's objectos-runtime. Three out-of-repo packages already have rows.Adding a second one would be the exact failure that file's header warns about — "A second description nobody checks is how that happens; one exported list is how it stops." So this PR adds no roster, no gate script and no
check:alias.The one real gap —
@objectstack/organizationshas no row, because the map is keyed byrequirestoken and that package isplugins[]-wired off the tenancy posture — needs apackages/spec/**edit, which was fenced out of this card. Routed to #11263 for the spec seat rather than done here.What actually changed
packages/console/README.mdno longer opens withpnpm add @objectstack/framework. The mechanism it described is real and just misnamed:@objectstack/clideclares@objectstack/consoleas a dependency (packages/cli/package.json), and both sit in the Changesetsfixedgroup, so any app that installs the CLI already gets a version-matched Console. Corrected rather than deleted — a reader is left with something runnable (npx create-objectstack).packages/cli/src/utils/console.tscarried the same fabricated name in the resolution-strategy docblock; same correction.packages/cli/src/commands/serve.ts— the multi-org fail-fast told an operator to add@objectstack/organizationsto their app and never said the runtime ships only with an enterprise/cloud subscription. That is the un-followable "add it to your dependencies" that framework#3366 exists to make legible — the boundaryplatform-capabilities.tsstates in its own words. The remedy now says so, so an operator without a licence can see that the two bullets below it are their actual path. Thedeclared-unresolvablebranch is untouched (that operator does have the package), and the strings the e2e suite pins —to THIS APPandNODE_PATH— are both preserved verbatim.What deliberately did NOT change
@objectstack/security-enterprise's install hint. It is a real enterprise package and the message already names its edition boundary, becauserenderCapabilityMessageinterpolates the roster'snoteon theenterprisebranch. "Fixing" it would have been the vacuity risk this card flagged.packages/plugins/plugin-audit/README.md(:365) andpackages/plugins/plugin-security/README.md(:42,48) — both in the declared surface, both re-read, both already correct: prose, not install commands, and each already states that the open edition ships no such runtime. No edit, which also keeps this PR clear of fix(security): walled postures elevate only the env-declared platform owner, never the first registrant #11211 / fix(plugin-security): compose controlled_by_parent across a chain (#11082) #11183 in that package.The test pin at
capability-preflight.test.tsis strengthened, not loosenedThe card flagged this assertion as the interesting one — it guaranteed we keep printing an install hint for an out-of-repo package. It stays, because the hint is correct; what it lacked was any proof that the hint carries its edition context. It now asserts the message contains the roster's
noteverbatim, read fromPLATFORM_CAPABILITY_PROVIDERSrather than copied as a literal — a copy here could drift from spec with both sides green.Ablation, both legs rebuilt-or-argued and confirmed on disk. The subject is imported relatively (
../src/utils/capability-preflight.js), andpackages/cli/vitest.config.tsaliases only@objectstack/service-cacheandcreate-objectstack— so noexports/distresolution is involved and the mutation takes effect without a rebuild. (@objectstack/spec/kernel, where thenoteis read from, does resolve throughdist, and was built first.) Replacingconst note = p!.note ? …with an empty string:Predicted direction was RED on that assertion alone; observed exactly that. The script carried a
trap … EXIT INT TERMrestore.Verification — all on the final commit
ce44f6057pnpm --filter @objectstack/cli exec vitest run test/capability-preflight.test.ts→ 15 passed (15);pnpm --filter @objectstack/cli typecheck→ clean.Gate families re-derived from the actual diff with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(no paths passed — the script reads its own change set), which added four the dispatch lead did not name, via its convention-triggered bucket. All 21 green, each exit code captured before any pipe:check:nul-bytes·check:changeset-gate-self-tests·check:objectui-changeset·check:published-files·check:route-envelope·check:slot-lookup·check:test-source-alias·check:type-check-coverage·check:type-source-resolution·check:cross-package-test-inputs·check:query-options-erasure·check:engine-double-contract·check:where-matcher·check:type-check-debt·check-adr-0087-registration·check-changeset-no-major·check-empty-changeset·check-ci-filter-parity·check-plugin-teardown-shape·check-affected-docs·check-published-readme-exportsQuoting each gate's own verdict rather than a bare exit code:
check:type-check-debtwas run against the built workspace closure (turbo run build --filter=./packages/* --filter=./packages/*/*→ 70/70 successful), so its verdict is a measurement, not a refusal.Repo-wide
pnpm lintwas narrowed, and the narrowing is measured rather than assumed — three pieces of evidence, all read from the tooling rather than guessed:.md) as "File ignored because no matching configuration was supplied."--format json: 5 results, 0 errors, 0 real warnings.eslint.config.mjsstates, with its own recorded positive control, that this repo "runs oneeslint.config.mjs, which never enables type-aware linting (noparserOptions.project, no typed@typescript-eslintrules) for ANY file" — so nothing in this diff can move the verdict on a file it does not touch.Findings filed, not fixed
packages/console/package.json's npmdescriptionstill names the fabricated@objectstack/framework#11261 —packages/console/package.json's npmdescriptionstill names@objectstack/framework. Outside the declared file surface, and it is the most visible remaining site (it renders on the npm page). One-line change.packages/console/README.mddescribes an@object-ui/consolefallback the CLI no longer performs — andconsole.tssays the opposite in the same repo #11262 —packages/console/README.md:27-31describes an@object-ui/consolefallback thatresolveConsolePath()no longer performs, contradictingconsole.ts:26-31in the same repo. Which side is stale depends on cloud's real Docker overlay target, which is not readable from here — so it was not guessed at.@objectstack/organizationsis an out-of-repo enterprise runtime with no row inPLATFORM_CAPABILITY_PROVIDERS— the roster that already answers #10921's question for every other one #11263 — thePLATFORM_CAPABILITY_PROVIDERSgap described above (spec-seat territory).Note for triage: per the ruling's standing execution note, #10920 waits on this same prior fact and is unblocked by what lands here.
ℹ️ Read-path note, corrected: the probe URL above is spelled
PKGNAMErather than with an angle-bracket placeholder because an earlier read of this body appeared truncated there. Measured afterwards against the REST API, that was not GitHub's sanitizer — raw storage keeps such fragments intact, and the dispatch comment on #10921 still holds its own angle-bracket placeholders verbatim. What drops them is the MCP issue/PR read path used to review the body. Nothing was lost on write; the plain placeholder is kept only so the URL reads correctly through either path.Generated by Claude Code
Generated by Claude Code