fix: consolidate version SoT + add pre-commit lockstep guard (AL-25, closes AL-29)#21
Merged
Merged
Conversation
…(AL-25) Adds scripts/check-version-lockstep.sh and wires it as a pre-commit local hook. Asserts that plugin/cli/package.json::version matches plugin/catalog/catalog.json::version on every commit that touches either file. Why: scripts/build-release.sh enforces a three-way version lock at release time (TAG vs package.json vs catalog.json). Drift between package.json and catalog.json on master would surface only when the next tag push fires the build, far from the commit that introduced the drift. This hook shifts that gate from release-time to commit-time so the divergence never reaches master. Why these two files only: the AL-29 SoT migration (riding in the next commit) makes plugin/cli/package.json the canonical version. Plugin source (bash entrypoint, TS modules) and bats tests now read it dynamically — nothing left to drift in those layers. The remaining drift surface is plugin/catalog/catalog.json, which carries its own version field consumed by `agentlinux upgrade` and shipped as a sibling release artifact (CAT-05). This hook locks that one pair. Implementation: pure bash plus sed. No jq dependency on contributor laptops. Strict regex match against the conventional semver shape (plus optional pre-release suffix) catches malformed bumps loudly. Diagnostic on mismatch shows both observed values and points at the build-release.sh release-time backstop. Self-tested locally: - happy path (both at 0.3.2) -> exit 0 - injected drift (catalog -> 0.3.3) -> exit 1 with clear diagnostic - restored -> exit 0 - pre-commit run --all-files -> Passed Refs: AL-25. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The release version "0.3.0" / "0.3.2" was duplicated across eight sites:
- plugin/bin/agentlinux-install AGENTLINUX_VERSION constant
- plugin/cli/src/index.ts commander .version() arg
- plugin/cli/src/catalog/loader.ts ?? fallback default
- plugin/cli/src/catalog/schema.ts ?? fallback default
- plugin/provisioner/10-agent-user.sh DOC-02 welcome-message string
- tests/bats/10-installer.bats INST-02 fallback default
- tests/bats/40-registry-cli.bats CLI-01/CLI-05 asserts + CAT-03 fixture
- tests/bats/50-agents.bats CATALOG path
- tests/bats/51-agt02-release-gate.bats CATALOG path
Bumping a release required mechanical edits at every site, and at
v0.3.2-rc1 one of those edits was missed (the AGENTLINUX_VERSION
constant in the bash entrypoint stayed at 0.3.0 while package.json
went to 0.3.2). The bats CAT-05 test reads the expected catalog
path from package.json dynamically, so it failed CI: the staged
catalog landed at /opt/agentlinux/catalog/0.3.0/ while the test
expected /opt/agentlinux/catalog/0.3.2/.
This change makes plugin/cli/package.json::version the single
source-of-truth. Every other site reads it dynamically:
TypeScript: a new plugin/cli/src/version.ts module walks up from
import.meta.url looking for package.json (covers dist/, dist-test/,
src/, and dev-tool layouts in one resolver — same pattern catalog/
schema.ts already uses for schema.json). Three call sites import
{ VERSION } from "./version.js"; the literal "0.3.x" defaults are
gone.
Bash entrypoint: a sed-extract from $BIN_DIR/../cli/package.json
runs at script load. No jq dependency (jq isn't preinstalled on
bare Ubuntu, and 30-nodejs.sh hasn't run yet at this point). The
extracted value is regex-validated; a malformed package.json fails
loudly before any provisioner step fires.
Bats tests: every "0.3.x" literal in a path assertion or a version
check is replaced with a $PKG_VERSION variable that runs jq once
at file scope against the bind-mounted /opt/agentlinux-src tree
(established by tests/docker/run.sh:150 before bats fires).
Provisioner welcome message: dropped the version reference rather
than wire it through the heredoc — the string was advisory, not
behavioral, and any version reference there would rot the moment
a new release shipped.
Engines floor bumped from >=20 to >=22 in the same file: every CI
workflow already pins setup-node@22 and the provisioner installs
Node 22 LTS, so the declared minimum was ahead of reality. With
the floor at 22, future TS code can rely on Node 22 features
without a peer-dep warning.
Verification: corepack pnpm test passes 112/112 unit tests against
the dist-test layout. The bash entrypoint --version flag prints
the package.json version when invoked. The new check-version-lockstep
pre-commit hook (introduced in the prior commit) confirms package.json
and catalog.json carry the same version on every relevant edit.
Refs: AL-25 (parent — lockstep guard rode in prior commit),
AL-29 (this consolidation; closing as duplicate of AL-25),
AL-30 (the four-bug fix that surfaced the sprawl),
AL-31 (the unpinned-resolution fix that paired with AL-30).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
50-agents.bats:16 commented that version pins are read from a literal 0.3.2 path, but the code below was switched to PKG_VERSION-derivation in the prior commit. Update the comment to reference the dynamic path so future readers don't grep for the literal and assume drift. Refs: AL-25. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
592cd37 to
a753a29
Compare
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.
Summary
Two-commit PR addressing the version-string sprawl that AL-25 (older, top-level Task) and AL-29 (newer, sub-task under AL-18) both filed against. AL-29 closes as duplicate of AL-25. Combined scope:
plugin/cli/package.json::version(was AL-29's scope).package.jsonandcatalog.jsonat commit time (was AL-25's exclusive carve-out).Commits
fix(precommit): lockstep guard for package.json/catalog.json version (AL-25)—93dd714scripts/check-version-lockstep.sh(pure bash + sed; no jq dependency on contributor laptops)..pre-commit-config.yamlas a local hook scoped to^(plugin/cli/package\.json|plugin/catalog/catalog\.json)$.scripts/build-release.shthree-way version-lock gate from release-time to commit-time so the divergence never reaches master.fix(version): consolidate version SoT to plugin/cli/package.json (AL-29)—d04bebbplugin/bin/agentlinux-install$BIN_DIR/../cli/package.json(regex-validated)plugin/cli/src/index.ts.version("0.3.2", ...)import { VERSION } from "./version.js"plugin/cli/src/catalog/loader.ts?? "0.3.2"default?? VERSIONfrom new moduleplugin/cli/src/catalog/schema.ts?? "0.3.2"defaultplugin/provisioner/10-agent-user.shtests/bats/10-installer.bats${AGENTLINUX_VERSION:-0.3.2}fallbacktests/bats/40-registry-cli.bats$PKG_VERSIONvariable derived once at file scopetests/bats/50-agents.batsCATALOG=/opt/agentlinux/catalog/0.3.2/...CATALOG=/opt/agentlinux/catalog/${PKG_VERSION}/...tests/bats/51-agt02-release-gate.batsNew module
plugin/cli/src/version.tswalks up fromimport.meta.urllooking forpackage.json— same patterncatalog/schema.tsalready uses forschema.json. Resolves correctly in bothdist/(production) anddist-test/src/catalog/(test build) layouts in one resolver.Engines floor bumped from
>=20to>=22in the same file: every CI workflow already pinssetup-node@22and the provisioner installs Node 22 LTS, so the declared minimum was ahead of reality. With the floor at 22, future TS code can rely on Node 22 features without a peer-dep warning.Verification
corepack pnpm test→ 112/112 unit tests pass against thedist-test/layout (the new walk-up resolver works there too).pre-commit run check-version-lockstep --all-files→ Passed.--versionflag prints the dynamically-extracted version when invoked from a checkout.Out of scope (deliberately, to keep the PR landable)
catalog.json::versionentirely (would need schema change + cascading updates; the new lockstep hook is the practical guard).plugin/cli/test/fixtures/*.json) — they're self-contained test data, not version-aware, and were never the source of drift.Test plan
gate-1-precommit(the new lockstep hook fires on package.json's engines change in commit 2 and Passes — already verified locally)gate-2-docker × {22.04, 24.04, 26.04}(every bats file now reads PKG_VERSION via jq; the bind-mounted source tree is established before bats fires pertests/docker/run.sh:150)gate-3-qemu × {22.04, 24.04}package.jsonto0.3.3in a follow-up commit, confirmagentlinux --versionreports0.3.3, the staged catalog appears at/opt/agentlinux/catalog/0.3.3/, the bats suite passes against that path without editing any other file. This is the AL-25 acceptance criterion.Refs: AL-25 (primary), AL-29 (will close as duplicate of AL-25), AL-30, AL-31