Stamp dev build IDs at pack time, drop the committed stamp - #2710
Merged
chalin merged 17 commits intoAug 9, 2026
Conversation
- Adds scripts/pack-stamp.mjs, wired as a theme prepack/postpack pair: dev tarballs gain the git-derived build ID, the committed manifest is restored; release/RC versions pack unchanged; shallow checkouts fall back to +g<SHA> - Normalizes committed versions to bare 0.16.1-dev (manifests, lockfiles, config buildId params) - Feeds the dev-site build-ID display from COMMIT_REF at Netlify build time - Fixes set-package-version --id mode silently bumping `latest` from the dev version core; aligns `dev` with the package version in that mode - Retires the check-version.sh hook helper, the set:version:git-info script, and the stamp-before-push contributor step (AGENTS.md, maintainer notes)
- Stamps the packed commit's HEAD SHA (X.Y.Z-dev+g<sha8>) instead of the over-main build ID: identifies the actual packed state, works on shallow checkouts, drops the get-build-id.sh dependency - Self-heals a manifest stranded by an interrupted pack (failed pack skips postpack): prepack restores any leftover backup before stamping - Pack tests force lifecycle scripts on, so the pack contract is tested even under a user-level ignore-scripts=true; tightens the stamp assertion to the +g<sha> form - Drops a stale set:version:git-info mention in get-build-id.sh
- Logs each config key by write outcome, not intent: the line-oriented writer silently skips keys with no line to land in, but the log claimed success (e.g. "buildId: (none) → X" with no buildId line written) - Matches buildId lines by key name alone: distinctive enough to need no anchor/comment marker, unlike latest/dev - Drops the tdBuildId anchor from the config files: aliased nowhere, and no longer needed as the line marker
- Makes the manifest authoritative in self-heal: a stranded stamp is stripped from the manifest itself and a leftover backup is discarded, never restored (a stale backup could downgrade the committed version) - Path-gates the unmarked-buildId match to tdVersion.buildId, leaving unrelated buildId keys in a config untouched - Counts an already-correct params.version scalar as a dev landing line, fixing a spurious not-written warning for docsy-example-style configs - Extracts packStamp() with injectable paths; adds scenario tests (stale backup, stranded stamp, release/RC, no-git) to test:tooling
…heal Per adversarial round 3 (GPT-5.6 Sol): - Routes the stamp message to stderr: lifecycle stdout is npm's result channel, so the message corrupted `npm pack --json` and the `tarball=$(npm pack --silent)` pattern; adds a stdout-contract test - Marks packs from a dirty theme/ tree as +g<sha8>.dirty: the packed bytes are not HEAD's, so a clean-HEAD stamp would claim a false identity; the pack test now expects the exact HEAD SHA, not just a hex shape - Widens self-heal to every stamp form ever produced (longer git abbreviations, .dirty, the retired +NNN-over-<branch>-<sha> committed form) and keeps the backup when a stamp form is unrecognized instead of discarding the only recovery copy - Scopes the post-release note to Docsy: docsy-example still commits a git-info dev version
chalin
force-pushed
the
chalin-m24-build-id-pack-stamp-2026-0808
branch
from
August 9, 2026 11:44
70da4bc to
d38d523
Compare
- Encodes the ordering invariant (stamp after the is:clean bracket) in one script instead of per netlify.toml command, and gives every build context the stamp without repeating the step
- Widens pack-stamp self-heal to every stamp form the repo's tooling writes: Netlify/--id bare-hex and timestamp forms were unrecognized, so a locally stamped manifest packed stale metadata that looked authoritative (F1) - --id on a release-core version leaves latest AND dev untouched: in the post-release window a Netlify build would announce a dev version that doesn't exist yet (F3) - _netlify:set-build-id fails loud on a missing COMMIT_REF instead of degrading to a timestamp masquerading as commit identity (F2) - Suppresses the per-key log for already-at-target values, ending the spurious buildId warning in the docsy-example flow (F4) - Notes the interrupted-pack residual (stamped working tree until the next pack) in the maintainer notes (F5)
- Corrects the maintainer-notes pack-stamp entry: the stamp is the packed commit's SHA, not get-build-id.sh's format described just above; RC versions also pack unchanged - Settles the stamp grammar's home at strandedStampRegex; the test fixture comment points instead of re-enumerating
- Rejects --id values that aren't semver build metadata (whitespace, embedded spaces, '+'): an invalid value would write a malformed version into package.json and fail a later npm operation far from the cause; validated at the parser so every caller is covered - Gives the _netlify:set-build-id guard a message for the Netlify log
- Treats a hyphen-leading --id value as the value unless it's a known flag: a leading hyphen is valid semver build metadata, and the silent timestamp reinterpretation was the last path bypassing the fail-loud validator - Routes the COMMIT_REF guard message to stderr, matching the pack-stamp stream discipline
- A `-`-leading next-arg is ambiguous between a value and a flag: fail loud with a named-value error rather than pick a side. Replaces the known-flags list, whose decay path was worse than the bug it fixed (a forgotten new flag would silently become a flag-shaped build ID); timestamp IDs remain reachable via a trailing --id or --id ''
- Retires the optional-value spellings (bare --id, --id ''), whose meaning had already drifted once (removal → timestamp across google#2547) and confused recall again on review: one shape remains, --id BUILD-ID, with 'now' as the explicit timestamp spelling - Rejections gained a hint pointing at 'now'; empty values now fail loud instead of mapping to a timestamp
chalin
marked this pull request as ready for review
August 9, 2026 13:22
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
main, benefit largely superseded #2707prepack/postpackstamp@docsy/themetarballs with the packed commit's SHA (X.Y.Z-dev+g<sha8>,.dirty-marked for dirty trees) and restore the committed bareX.Y.Z-dev; release/RC versions pack unchangedprepackself-heals after an interrupted pack: a stranded stamp (any tooling-produced form) is stripped from the manifest; a leftover backup is discarded, never restorednpm pack --json/--silentstdout intactCOMMIT_REFat Netlify build timerm .git/hooks/pre-commit .git/hooks/pre-push) once this lands--idmode recomputedlatestfrom the dev-version core, silently bumping it (v0.16.0 → v0.16.1 while at 0.16.1-dev); it now leaveslatestuntouchedtdBuildIdanchor is dropped:buildIdlines match by key name)--idnow requires a value validated against semver build-metadata grammar, withnowas the explicit timestamp spelling; the former optional-value forms (bare--id,--id '') and hyphen-leading values fail loud instead of being silently reinterpretedignore-scripts=trueprepack); the manifest inside is stamped (cosmetic, dev-only)ignore-scripts=trueconfigs skipprepackon directnpm packruns (CI, Netlify, and the tests are unaffected); the tree state remains those setups' identifier