Skip to main content
Welcome. This site supports keyboard navigation and screen readers. Press ? at any time for keyboard shortcuts. Press [ to focus the sidebar, ] to focus the content. High-contrast themes are available via the toolbar.
serard@dev00:~/cv

Pinning Is the Start

Pinning matters because surprise updates are onboarding failures.

If the company cannot say which versions are expected, the newcomer becomes the version resolver. They install the latest Git, the latest Docker, the latest SDK, the latest IDE extension, and then discover the project expects something else.

Pinned baselines fix that class of failure:

ToolchainBaseline
  git = 2.51.0
  docker = 29.1.3
  dotnet = 10.0.100
  node = 22.20.0

But pinning alone is not enough. A pinned baseline that never updates becomes a museum. The team avoids change until a security patch or platform migration forces a painful jump.

The right model has two lanes:

Lane Purpose
baseline stable toolchain used by newcomers and daily work
candidate isolated update checks against one proposed version transition

The baseline protects developers. The candidate lane protects the future.

The same two lanes apply to modules, not just tool versions. A module referenced by #t: or #cr: is frozen and rides the baseline; a module referenced by #b: is a moving source and is therefore a candidate — it goes through this lane before any profile is allowed to pin it. Pinning a module is pinning a version. Part VII defines the reference syntax.

Diagram
A candidate transition is isolated to diagnose, then matrixed to approve coupled versions. Only evidence from both gates promotes it into the baseline newcomers actually receive; a failure is quarantined, never shipped to a first day.

Isolate, Then Matrix

Updates should be isolated whenever possible, but not forever.

Bad update practice:

update Git
update Docker
update Node
update .NET
update VS Code extensions
run setup
something fails

Good diagnostic practice:

given current baseline
when Docker changes from 29.1.3 to 29.2.0
then run the complete onboarding readiness probes
and keep every other tool pinned

This is exactly the kind of failure discussed in Typed Docker: tool versions change behavior, flags appear or disappear, output formats shift, and assumptions break at runtime. The onboarding system should catch that before the update becomes the newcomer's problem.

Isolation answers one question: "Did this one transition break the setup?"

But onboarding also has compatibility questions. Docker and WSL can break together. Node and pnpm can break together. A .NET SDK and a VS Code extension can break together. A proxy tool and a certificate bundle can break together. For those cases, the setup contract needs a matrix:

updateMatrix:
  name: "runtime-baseline-2026-07"
  strategy: pairwise
  axes:
    docker: ["29.1.3", "29.2.0"]
    dotnet: ["10.0.100", "10.0.200"]
    node: ["22.20.0", "22.21.0"]
    pnpm: ["11.2.2"]
  run:
    - setup
    - firstClone
    - projectReadiness
  acceptWhen:
    - all required combinations pass
    - no manual repair happened
    - evidence includes every runner profile in scope

The rule is: isolate to diagnose, matrix to approve. The matrix does not replace the isolated lane; it prevents false confidence after the isolated lane passes.

The update model should exist for every important tool or coupled group:

  • Git and OpenSSH.
  • Docker, Docker Compose, Podman, LXC.
  • SDKs such as .NET, Node, Java, Python, Rust.
  • Package managers such as npm, pnpm, NuGet, Maven, pip.
  • IDE and extension versions.
  • Corporate certificate and proxy tooling.
  • Security scanners and pre-commit hooks.

Each isolated lane answers one question: "Can a fresh developer still become ready if this one thing changes?" Each matrix answers the next question: "Can the supported combinations still become ready together?"

The Transition Is the Domain Object

A version update is not just a number change. It is a domain object.

VersionTransition
  tool: "internal-cli"
  from: "3.3.2.2"
  to: "3.3.4.3"
  scope: "candidate"
  strategy: "isolated"
  probes:
    - install
    - version
    - authenticate
    - clone
    - build
    - run smoke test
  decision:
    - accept
    - reject
    - quarantine

That model gives the company a vocabulary:

during update from 3.3.2.2 to 3.3.4.3
  keep the baseline frozen
  create fresh instances
  apply only this transition
  run ProjectReadiness
  compare ReadinessEvidence

The transition can now be reviewed. It has evidence. It has failures. It has an owner. It can be retried. It can be rolled back.

A matrix is the same idea lifted one level:

during update matrix runtime-baseline-2026-07
  keep the baseline frozen
  generate candidate combinations
  run ProjectReadiness on every required runner profile
  accept only if the matrix evidence is complete

No Newcomer Should Discover Update Drift

The worst possible update test is a first day.

When a newcomer arrives, the company is trying to build trust. If the first experience is "the setup is broken because Docker changed yesterday," the company has spent that trust on a preventable failure.

CI-ing setup changes that — and Part V is where those jobs get their fresh ground, one Packer-built machine per matrix combination, each standing up a fresh project instance:

  • scheduled jobs test the baseline on fresh instances
  • candidate jobs test one transition at a time
  • matrix jobs test the supported combinations that matter
  • failed updates remain outside the baseline
  • accepted updates update one source of truth
  • readiness evidence documents why the update is safe

The rule is simple:

No tool update reaches newcomer setup until its isolated transition and required matrix combinations have passed the same readiness contract as the baseline.

That is how pinning and iteration coexist.

An update you have tested on fresh instances is an update no newcomer has to discover.

Test your onboarding.

⬇ Download