Commit 076bb97
fix(docs): plugin-spec's package.json example silently installs a 2.x CLI — both
Fixes #17378
Clause-②: no
This diff is one hand-written docs page. It adds no schema key, no
closed-set member, no published export and no registry entry — nothing
an author can write gets wider.
## The defect
`content/docs/protocol/kernel/plugin-spec.mdx` publishes the protocol's
own plugin-packaging `package.json` example. Its dependency block
declared:
```
"dependencies": { "@objectstack/core": "^2.0.0" }
"devDependencies": { "@objectstack/cli": "^2.0.0", "typescript": "^5.3.0" }
```
Both packages ship at **17.4.0** (`packages/cli/package.json`,
`packages/core/package.json`, confirmed against the registry: `npm view
@objectstack/cli version` → `17.4.0`, `dist-tags.latest` → `17.4.0`;
same for `@objectstack/core`). A caret pins the major, so `^2.0.0`
admits no 17.x — the card's arithmetic (`17.4.0` is not in `^2.0.0`)
holds on today's tree.
### What an author actually gets — measured, not assumed
The card deliberately did not claim whether a 2.x was ever published,
because it does not change the verdict. It is worth recording anyway,
because it names the failure mode:
- `@objectstack/cli` — 160 published versions, including `2.0.0` …
`2.0.7`.
- `@objectstack/core` — 157 published versions, including `2.0.0` …
`2.0.7`.
So the block **resolves**. It is not an install error — it is worse than
one: an author copying the page silently installs
`@objectstack/cli@2.0.7`, fifteen majors behind, and then runs the
page's own `"package": "os plugin build"` script on that 2.x CLI. A
failed install is loud; this is quiet.
Both packages are public — no `private: true`, `publishConfig.access:
public`, `files: ["dist", "README.md", "CHANGELOG.md"]` — and
`@objectstack/cli` is the right devDependency for this example, since it
is the package whose `bin` provides the `os` binary the block's own
`scripts` invoke.
## The range chosen, and the reading behind it
**`^17.0.0`** — the current major's floor, caret.
1. **Both other hand-written carriers in this repo already teach exactly
that**, and the card named them as the correct ones:
`packages/create-objectstack/src/templates/blank/package.json:26` and
`skills/objectstack-platform/SKILL.md:607`, both `"@objectstack/cli":
"^17.0.0"` beside `"typescript": "^5.3.0"`. Picking anything else would
make this page the only carrier teaching a third style.
2. **There is an authority, and it is not a constant — it is a
function.** `packages/cli/src/commands/init.ts` resolves every
scaffolded `@objectstack/*` range through `getCliVersion()` /
`pkgVersion()`, which caret-pins to the running CLI's own version, over
a comment that states the rule: every `@objectstack/*` package in this
monorepo is published on one shared release version. That is
caret-on-the-current-major with a live floor. A hand-written page cannot
carry a live floor, so it carries the major's — which is what the two
carriers above do.
3. **`^17.4.0` was rejected**: it admits exactly the same set for a
reader installing today, and rots on every minor release, while
`^17.0.0` only moves when the major does. The page now says so in one
sentence so the next reader knows what to update and when.
The prose under the block already named `SCAFFOLD_TYPESCRIPT_RANGE` as
the authority for the `typescript` floor — the shape #16756 established
on the adjacent line. This PR extends the same sentence to name
`getCliVersion()` for the `@objectstack/*` ranges, so the page teaches
one range style rather than two.
## ⭐ Declared: the fix covers TWO lines in the block, not the one on the
card
The card names `@objectstack/cli` at what was then line 707.
`@objectstack/core`, one line above inside the same `package.json`
example, carried the **identical** defect — `^2.0.0` against a published
17.4.0 — and the card's triage comment anticipated exactly this ("a
census keyed to one literal repairs one key and leaves its neighbours
... re-derive the whole block against publishable versions").
Repairing only the `cli` line would have left the block still
uninstallable-as-intended, so the ruling's invariant ("the published
example resolves to today's line") would not have been restored. Both
lines are in the same JSON object, same defect class, same mechanical
shape, and no other claim holds that section. Nothing else in the file
was touched.
## ⛔ NOT touched — reported, not swept
Five further `^2.0.0` occurrences exist on this page. **None is the same
defect** and none was changed:
| line | text | why it is out |
|---|---|---|
| 60, 436 | `'@objectstack/core': '^2.0.0'` | plugin **manifest**
`dependencies`, a `Record` of packageId to versionRange resolved by the
kernel, not by npm. Different surface, different resolver. |
| 71, 462 | `'@objectstack/ui': '^2.0.0'` | same manifest surface, under
`peerDependencies`, which the page's own callout marks proposal-only
("the schema declares neither, so nothing resolves them"). |
| 937 | `'@objectstack/core': '2.0.0', // Not '^2.0.0'` | a deliberate
exact-pin-vs-caret teaching example; the number is the lesson's prop,
and changing it is a content decision, not a mechanical repair. |
One further finding surfaced while measuring those and is **reported,
not filed and not fixed**: `@objectstack/ui` returns **404** from the
registry (`npm view @objectstack/ui version` → `E404 ... is not in this
registry`), so those two manifest lines name a package nobody can
install. It sits on a surface the page already labels proposal-only, so
it is a different card from this one.
## Verification
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` (no path list — derived from git): **40
families**, all run, exit codes captured to disk before any pipe.
**40/40 exit 0.**
- Reconciled: `dispatch-gates --ran` → `40 derived, 40 run, 0
NOT-MEASURED, 0 UNRUN` (a derived zero — every family recorded an exit
code and none is 3).
- First sweep produced three `exit 3` PREREQUISITE NOT MET results
(`@objectstack/lint`, `@objectstack/formula`,
`@objectstack/client-react` unbuilt). Those are NOT MEASURED, not
failures: the prerequisites were built and the **whole** sweep was
re-derived and re-run. The 40/40 above is that second sweep.
- Builds ran under `scripts/pm/os-verify-lock.sh` (slot `issue-17378`),
both `VERDICT command-exit 0`.
- **eslint, narrowed and the narrowing proven.** Targeted run: `eslint
content/docs/protocol/kernel/plugin-spec.mdx --no-inline-config --format
json` → exit 0, 1 result entry, 0 errors, 1 warning, and that warning is
`File ignored because no matching configuration was supplied.` ①
Population read from eslint's own config: every `files:` selector in
`eslint.config.mjs` is a TS/JS glob
(`**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}` and narrower); `.mdx` matches
none, and the programmatic `ESLint#isPathIgnored` on this path answers
`true`. ② Count read from `--format json`, as above. ③ Invariance:
`eslint.config.mjs` states, and grep confirms, that **no** config block
sets `parserOptions.project` and no typed `@typescript-eslint` rule is
enabled — with type-aware linting off, this diff cannot move the verdict
on any untouched file. This PR's eslint result is therefore identical to
`main`'s, by construction.
- Counted with `grep -o | wc -l` throughout, each count paired with a
firing control: the two replaced literals were `1` and `1` before and
`0` and `0` after, the two single-quoted manifest occurrences stayed `2`
throughout (they must not move), and the card's nonsense probe
`"@objectstack/zzzz"` returns `0`.
- Control-byte self-scan over the changed file: `grep -naP
'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'` → no match (exit 1), with the class
proven to fire on an injected `\x01`.
- `Build Docs` and `Test Core` are path-scheduled CI jobs with no local
invocation; declared to CI, **NOT MEASURED** here.
## Changeset
`skip-changeset`. Measured on the publish surface rather than asserted:
`apps/docs` is `private: true`, and enumerating the `files[]` array of
every `package.json` in the workspace finds **no** published package
shipping any `content/` path (firing control on the same probe:
`packages/cli`'s `files[]` reads back
`["dist","README.md","CHANGELOG.md"]`, so the probe is reading real
arrays). This diff publishes nothing.
## Acceptance notes
- `content/docs/protocol/kernel/plugin-spec.mdx` is also the subject of
#15952 (`pm:epic`, reserved). That card edits a later section of the
page; this change is confined to the npm `package.json` example and the
paragraph immediately under it.
- Noted, not filed — no `@objectstack/*` version range in
`content/docs/**` is covered by any gate. `check:vendor-version-stamps`
exists and is green, but it does not read these. Successor: none
identified; the next author to touch this page has no mechanical signal,
which is why this same block drifted twice.
---
_Generated by [Claude
Code](https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk)_
Co-authored-by: Claude <noreply@anthropic.com>@objectstack/* ranges repaired to ^17.0.0 (#18186)1 parent a81a9d6 commit 076bb97
1 file changed
Lines changed: 8 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
700 | 700 | | |
701 | 701 | | |
702 | 702 | | |
703 | | - | |
| 703 | + | |
704 | 704 | | |
705 | 705 | | |
706 | 706 | | |
707 | | - | |
| 707 | + | |
708 | 708 | | |
709 | 709 | | |
710 | 710 | | |
| |||
723 | 723 | | |
724 | 724 | | |
725 | 725 | | |
726 | | - | |
| 726 | + | |
| 727 | + | |
| 728 | + | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
727 | 732 | | |
728 | 733 | | |
729 | 734 | | |
| |||
0 commit comments