Skip to content

Release v0.12.2 - #29

Merged
jdogresorg merged 11 commits into
masterfrom
release/v0.12.2
Sep 1, 2026
Merged

Release v0.12.2#29
jdogresorg merged 11 commits into
masterfrom
release/v0.12.2

Conversation

@jdogresorg

Copy link
Copy Markdown
Contributor

A patch train that moves the carrier alone. Every component keeps the tag it already carries: a gap in the manifest means unchanged, not skipped.

It exists because v0.12.1 shipped without the validator commands its own documentation describes. An external operator followed the published quickstart, installed the release, ran validator stake, and was told there was no such command. The documentation was accurate; the release was missing the feature.

Carries

  • validator init / stake / unstake: mint, stake and withdraw against the public network, so an operator can join before installing any stack
  • an unrecognised service name is refused with the list of valid ones, instead of silently expanding to every service on every coin and network
  • a coin image builds from a context that holds its Dockerfile, and never writes live credentials into the tracked config template
  • a mutating command waits out a busy lock instead of losing the run
  • the next step printed after validator init names the release rather than a branch

Classification: state-neutral throughout (operator tooling, CLI argument handling, build context, lock behaviour). Nothing changes what state is derived from existing bytes, so it ships ungated as a patch per the hotfix classification rule.

Verification: 1766 passing / 0 failing on this branch, including the release-manifest guard. README counts refreshed to match.

`bootstrap create` is a mutating subcommand, so it takes the same command lock
as `update` and `reset`. A bootstrap publish that started while a deploy was
underway therefore failed every combo in the same second and reported it as a
broken publisher, so the run exited and the archives it should have cut simply
never appeared. That is how a scheduled tracker publish was lost with nothing
to show for it but stale archives found by hand hours later.

Mutating commands now accept a wait, defaulting to zero so an interactive
update or reset still refuses a held lock immediately rather than appearing to
hang. The lock helper already polls and takes the lock the moment it frees, so
no retry logic was added; unattended callers just ask for the wait.

The publisher asks for thirty minutes and reports a combo it could not start
as locked, which tells the operator the box was busy rather than sending them
to look for a fault in the machinery or the source.
The wait for a busy command lock lived in the CLI, so a fleet running a pinned
release does not get it. The publisher is a standalone script that can be
updated on its own; the CLI cannot be moved off a release pin one file at a
time, because a single file carries requires that the pinned tree has no
modules for.

Move the retry into the publisher, where it works against whatever CLI the box
carries, and pin the CLI's own wait to zero so the two cannot compound. Budget
and poll interval are both settable, and a create still locked when the budget
runs out is reported exactly as before.
Levelling develop with master, the step that closes a release train. Commits that
reach master without coming back leave the branch all work lands on missing what
shipped.

README conflicted on test counts alone: the currency pass recorded master's
numbers while develop already carried higher ones from the train's own refresh.
Kept develop's, because develop is the tree being merged into and its counts were
generated against it. The stats tool regenerates them, so the next refresh
supersedes both.
`validator init` ends by telling a new operator to run `install master
xchain-hub`. That is an unpinned tracking install, it contradicts every other
instruction we give, and it is printed at the exact moment someone is deciding
what to run.

The ref is derived from this CLI's own version, which is the platform version, so
the hint stays on the release the operator is holding instead of rotting the way
a hardcoded one does.
…rfile

The image is built with the coin's own directory as the Docker context, so that
directory must hold both the downloaded daemon tree and the Dockerfile and conf
template the repo ships in git. Only the daemon tree is downloaded there, so on
the default layout the scaffold was present by accident: the build directory
already was the repo's crypto_nodes. Point the crypto-nodes directory at a
separate volume, which the README recommends for a small root partition, and the
build context held nothing but the tarball. Docker reported "failed to read
dockerfile" after the entire download had already run.

Stage the scaffold before every build, and fail closed naming the missing path
rather than letting docker report a two-byte build context.

Two defects in the same path go with it. The credential injection was skipped
whenever the conf was absent, which is exactly the custom-directory case, so a
build there would have shipped an image carrying the placeholder tokens as its
RPC credentials; it now fails closed. And the substitution wrote back into the
tracked conf template, leaving every host that ever built a node with a dirty
worktree holding live credentials. It now writes a gitignored 0600 generated
sibling and never touches the template.
An argument that matched no service, coin or network was silently dropped, and
the service slot kept its default of "all". So `install master hub` did not
refuse the unrecognized name, it expanded to every service on every coin and
network. An operator reaching for one service got the whole platform.

The trap was already known for one token: `xchain-node` is guarded by name,
with a comment explaining that a dropped argument leaves service='all'. That
reasoning was never generalized, so every other typo and every short name still
fell through.

Refuse anything unrecognized and name the valid services, coins and networks in
the refusal. The branch slot still accepts an arbitrary string, so the refusal
only fires once that slot is spoken for.

Shared services are also aliased now. The canonical names carry an `xchain-`
prefix that is easy to omit, `explorer` already had that treatment, and the
others did not, so `recreate hub` matched no container and read as though the
hub simply could not be recreated. hub, sync and db now resolve to their
canonical names in both the argument resolver and the command filter, because
the commands that bypass the resolver hand the operator's raw token straight
through.
A patch train that moves the carrier alone. Every component keeps the tag it
already carries, which is what it means for a version to be the platform version
at which a component last changed: a gap is unchanged, not skipped.

It exists because v0.12.1 shipped without the validator commands its own
documentation describes. Someone following the published quickstart installed the
release, ran `validator stake`, and was told there was no such command. The
documentation was right; the release was missing the feature.

Also carries an unrecognised service name being refused with the list of valid
ones rather than silently expanding to every service on every coin and network, a
coin image building from a context that holds its Dockerfile, and a mutating
command waiting out a busy lock instead of losing the run.
@jdogresorg
jdogresorg merged commit 4176f79 into master Sep 1, 2026
7 checks passed
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