Skip to content

Versioning & compatibility

The versioning model exists to make one promise credible: the platform can upgrade itself, dependencies, security patches, new features, without breaking a template that hasn’t changed.

Every published {name}/{version} is frozen forever. Tenants render the exact version they’re pinned to; caches (engine memory, CDN) never need invalidating because the content under a version can’t change. Ship fixes as new versions:

  • Patch (1.0.1), visual fixes, CSS tweaks, no new content requirements.
  • Minor (1.1.0), new supported sections/pages, new settings.
  • Major (2.0.0), a redesign, or adopting a new contract major.

Your manifest’s format (port60-liquid@1) names the contract major you’re written against, the dialect whitelist, section catalogue, island registry, CSS tokens, and render context as a set. Within a major, the contract is additive-only:

  • Section types and fields are added, never removed or re-shaped.
  • Context variables are added, never removed.
  • CSS tokens are added (with working defaults), never removed or repurposed.
  • The dialect only ever widens.
  • Island styling APIs are stable; island internals are explicitly not.

So a template written against port60-liquid@1 today still validates and renders against every future platform release that supports major 1, that’s the Android-style compatibility promise, and it’s enforceable because the contract is machine-readable.

Before any platform release that touches the template system goes live:

  1. Contract-diff gate, CI diffs the contract files against the previous release and fails anything non-additive within a supported major.
  2. Template regression fleet, every published template@version is re-rendered against its fixtures and golden output; a rendering difference blocks the release, not your template.
  3. Multi-major engine: when port60-liquid@2 arrives, the engine keeps rendering major 1 artifacts side-by-side. A new major is an invitation to upgrade, never an eviction.

(These gates are commissioning as the platform approaches go-live; the contract they enforce is already the one you’re building against.)

  • Declare honestly: supports should list exactly what you render, islands included.
  • Don’t reach past the contract, undocumented class names, un-listed context variables, and island internals are the only ways a platform upgrade can surprise you.
  • Watch planned islands you declared: they begin rendering when they ship, so leave sensible space around them.

Since 2026-08-09 the Android-model promise is mechanically enforced on every platform change:

  • The contract freeze, contract v1 may only grow. A frozen lock captures every surface your template may depend on (dialect tags/filters, section types, island styling APIs, context variables and their scopes, tokens, fonts, manifest rules); any removal or narrowing fails the platform’s own test suite and CI. Breaking changes require a new format major, never a quiet edit to @1.
  • The regression fleet, every published template@version is re-rendered against the contract fixtures on every platform change and compared to stored goldens. If a platform change would alter your template’s output, the platform’s release fails, not your template.
  • Multi-major engine, when port60-liquid@2 ships, @1 artifacts keep rendering through their own contract set, with a published deprecation window before any retirement.

Your obligations still end at conformance; keeping your template rendering is our job.

Published versions never need you to act; the platform renders them forever. Your working copy is different: npx @port60/template-kit@latest upgrade moves an existing template onto the latest kit and contract, regenerates the agent briefing, and reports what (if anything) the new contract asks of you. See the template kit.