Skip to content

templates: float the engine with a floor, keep the tool pinned - #670

Closed
jonit-dev wants to merge 1 commit into
developfrom
fix/template-engine-floors
Closed

jonit-dev wants to merge 1 commit into
developfrom
fix/template-engine-floors

Conversation

@jonit-dev

Copy link
Copy Markdown
Contributor

Problem

Every starter kit pinned the engine exactly ("@threenative/core": "0.3.13"). Templates ship inside create-threenative, so the only way a kit ever got a newer engine was a full CLI repack — a lib patch published today reached new projects only after the next CLI release. Owner's ask: "I just want to make sure I don't need to care about updating starter kits or sandbox shit anymore; when a user installs it, it gets the latest."

Change

  • Templates ship ">=0.3.13" for @threenative/* (open floor, no ceiling — a 0.4.0 also lands in new projects without a repack), and keep create-threenative exact.
  • A game already scaffolded stays frozen by its own pnpm-lock.yaml; only new scaffolds float.
  • scripts/version-range.ts owns the specifier form. The pin gate, the release preflight, the release pin writer and the publish-state registry check all read it.
  • assertEnginePair now accepts any core at or after the paired release (src/core-pair.ts) instead of exact equality, so a newer engine is no longer a refusal on a correct fresh install. assertMcpShims and the engine's tn_version_handshake still fail closed on a pair that cannot work.
  • check-publish-state resolves a range's floor (the release the kit was tested against) instead of handing the registry an unreadable range.

Generated project after this change:

@threenative/core            -> >=0.3.13
@threenative/physics         -> >=0.3.13
@threenative/ui              -> >=0.3.13
@threenative/assets          -> >=0.3.14
@threenative/playtest        -> >=0.3.13
@threenative/runtime-native  -> >=0.3.13
create-threenative           -> 0.2.18   (the tool stays exact)

Sandbox

pnpm sandbox and CI's scaffold-from-tarballs substitute tarballs by package name, so the specifier never reaches the resolver there — sandbox games were already current. New sandbox games inherit the same floors.

Verification

  • pnpm typecheck clean.
  • 301 focused vitest cases pass: scripts/__tests__/{version-range,check-version-pins,release,check-publish-state,prepare-release,typescript-toolchain}.spec.ts, packages/create-threenative/__tests__/{core-pair,doctor-fix,doctor,engine-catalog-plugin,playtest}.spec.ts.
  • tsx scripts/check-version-pins.ts passes.
  • Real createProject({ install: false, template: "starter" }) emits the block above.
  • pnpm scaffold:pin re-pinned 16 kits; only kit moved, every shared hash is unchanged, i.e. the diff is exactly the manifest.
  • Pre-push ci:fast: agents, docs, lint, drift all pass.

Not run here: full pnpm test, playtests, pnpm publish:check (network).

Known ceiling

Within an open floor a bad patch reaches new projects without waiting for a CLI release; the mitigation is npm deprecate on the bad version, which reaches every game. Existing games are protected by their lockfile.

A kit scaffolded today installed whatever engine was current when
create-threenative was last published, because every template pinned the
workspace version exactly. A lib patch reached new projects only after a
full CLI repack, and there was no way to publish the two together.

Templates now ship `>=0.3.13` for `@threenative/*` and keep
create-threenative exact: pnpm resolves the newest published engine at
install, so a release never has to touch a template again. A game already
scaffolded stays frozen by its own pnpm-lock.yaml.

- scripts/version-range.ts owns the specifier form; the pin gate, the
  release preflight and the release's pin writer all read it.
- assertEnginePair accepts any core at or after the paired release instead
  of exact equality, so a newer core is no longer a refusal on a correct
  install. assertMcpShims and the engine's tn_version_handshake still fail
  closed on a pair that cannot work.
- check-publish-state resolves a range's floor, the release the kit was
  tested against, instead of handing the registry an unreadable range.
@jonit-dev

Copy link
Copy Markdown
Contributor Author

Content is on main as e64ab4a (direct push at owner's request). develop catches up on the next promotion merge.

@jonit-dev jonit-dev closed this Nov 12, 2026
@jonit-dev
jonit-dev deleted the fix/template-engine-floors branch November 12, 2026 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant