Skip to main content

0012 — Portal version stamp from the built commit

Status: Accepted · Date: 2026-09-25

Context​

Every app's version is resolved from git at build time by scripts/version.mjs. No file in the tree carries a version number. The portal used to read the nearest portal-v* tag, the way the tracking app reads v*.

The production portal (https://portal.enode.ai) always showed the version dev. The live bundle had appVersion:"dev" baked in. Vercel builds the portal from a shallow clone without tags, so the tag lookup failed and the script fell back to dev without logging anything. With the full history, the same release commit resolves to 1.0.1 (67).

Two further problems made the tag scheme a poor fit for the portal:

  • A release tag has to exist before the deploy is built. The deploy is built on the merge into release, but a tag is usually set after that merge.
  • No portal-v* tag had been set since portal-v1.0.1 (2026-08-28), so even a working lookup would have shown a stale version.

Decision​

The portal is stamped with the commit it was built from, not with a release number:

ValueSourceExample
NEXT_PUBLIC_APP_VERSIONcommitter date of HEAD, as YYYY.MM.DD2026.09.22
NEXT_PUBLIC_APP_BUILDfirst seven characters of the HEAD hashe42a1a2

useAppVersion joins them into 2026.09.22 (e42a1a2).

The portal is a website. Every user always runs the latest deploy, so a release number would answer no question. A support report only needs to identify the code that was running, and the hash does that exactly. This is the common practice for continuously deployed web apps.

The stamp needs only the checked-out commit: no tag, no history, no manual step. It therefore works in Vercel's shallow clone as it is.

What stays the same​

  • The tracking app keeps its v* tags. Play and the App Store require a real release version and a monotonic build number.
  • The backend reads no portal version. The app-version header is native-only because it is not in the API's CORS allow-list, so the format is free to choose.
  • The existing portal-v* tags stay in place but are no longer read.

Consequences​

  • The portal shows no marketing version such as 1.0.2 any more.
  • A local next dev of the portal shows the checked-out HEAD, even with uncommitted changes on top.
  • When no git checkout is available, the version is dev, and scripts/version.mjs prints a [version] warning to the build log.

See Deployment → "Versioning".