Skip to content

chore(deps): pin zmk + zephyr to SHAs, add deps-check for upstream updates - #42

Merged
rdlu merged 1 commit into
mainfrom
chore/pin-zmk-zephyr
Sep 2, 2026
Merged

rdlu merged 1 commit into
mainfrom
chore/pin-zmk-zephyr

Conversation

@rdlu

@rdlu rdlu commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Completes the pinning started in #38. Every west project is now SHA/tag-pinned, so the same repo commit always produces the same firmware.

Pinning zmk alone would not have worked

The dependency chain floats in two places:

config/west.yml   →  zmk     @ v0.3-branch+dya    ← branch  (ours)
zmk/app/west.yml  →  zephyr  @ v3.5.0+zmk-fixes   ← branch  (NOT ours)
                     nanopb, zmk-studio-messages  ← SHA ✓
zephyr/west.yml   →  ~60 Zephyr modules           ← SHA ✓

v3.5.0+zmk-fixes is refs/heads/, a branch — verified against the remote. Pinning zmk to a SHA freezes its manifest file, but that file still says revision: v3.5.0+zmk-fixes, a name west re-resolves on every update. Zephyr would have kept floating and the pin would have looked complete while being half-done.

So config/west.yml now redeclares zephyr too, relying on west's rule that a top-level project definition wins over the same name in an imported manifest. The override replicates zmk's entry verbatim — clone-depth: 1 plus the entire import: name-blocklist — with only revision differing.

Project Was Now
zmk branch v0.3-branch+dya 4493783e
zephyr branch v3.5.0+zmk-fixes (via zmk's manifest) dacab4875, overridden here

New task: mise run deps-check

Pinning trades silent auto-updates for explicit ones, so this adds what replaces them. It's the counterpart to doctor and looks the opposite way:

Task Question
doctor Does the workspace match the manifest? (drift from the pin)
deps-check Has upstream moved past the manifest? (updates to the pin)

Each pin carries a # track: <ref> comment naming the upstream branch its SHA came from, or tags to compare against the newest remote tag. deps-check reads those and does one git ls-remote per project — no fetching, no clones — then reports what moved and the steps to take it.

The first run already found two real updates, which is the whole point:

   eyelash_sofle                        main              4848e21f8c42  UPDATE -> cad147725279
   zmk                                  v0.3-branch+dya   4493783ef88c  up to date
   zephyr                               v3.5.0+zmk-fixes  dacab4875df7  up to date
   zmk-behavior-runtime-sensor-rotate   main              8b1125ed676c  up to date
   zmk-module-ble-management            tags              zmk-v0.3.0.0  up to date
   zmk-module-battery-history           main              307755dd2ad4  up to date
   zmk-module-settings-rpc              main              78f86df9e6c5  up to date
   zmk-module-runtime-input-processor   tags              zmk-v0.3.0.0  UPDATE -> zmk-v0.4.0.0

Neither is taken in this PR. Bumping the board/shield module, or jumping a module across a major version, each deserves its own change and its own build verification — that's exactly the deliberateness pinning is for.

Verification

  • ✅ west update resolves correctly through the zephyr override — same SHAs, all 20 modules/hal directories present. This was the real risk (clone-depth: 1 against a raw SHA rather than a branch name), so it was tested rather than assumed.
  • ✅ mise run doctor passes
  • ✅ Both halves build byte-identically to before the pin: left 420072 B flash / 111186 B RAM, right 276908 B / 63660 B. The pins resolve to exactly what was already building, so this changes nothing about the firmware — only its reproducibility.
  • ✅ deps-check output above, verified against the actual remotes

Trade-off, stated plainly

You no longer get cormoran's fixes automatically. That is the cost, and it is real — if nobody runs deps-check, this repo can sit on a stale base indefinitely. It's worth it because the old failure mode was silent: two CI runs of an unchanged repo could produce different firmware with no signal at all, and you flash straight from CI artifacts. Explicit staleness you can check for beats silent drift you can't.

Churn context: v0.3-branch+dya last moved 2026-05-04; v3.5.0+zmk-fixes last moved 2023-09-07. Low, but "hasn't happened in four months" is not "won't happen".

One rule to remember

Bumping zmk may require mirroring a change into config/west.yml. If a new zmk revision changes its own zephyr entry (revision, clone-depth, or the blocklist), the override here goes stale silently. Called out in CLAUDE.md, in a comment in config/west.yml, and in deps-check's own output.

Docs

  • CLAUDE.md — the zephyr-override rule, the mirroring warning, deps-check in the workflow list
  • README.md — new "3c. Keeping dependencies current"

Implementation note: deps-check uses a TOML literal string ('''), because its embedded Python needs regex escapes (\s, \S, \d) that a basic string would try to read as TOML escapes.

…dates

Completes the pinning started in #38. Every west project is now SHA/tag-pinned,
so the same repo commit always produces the same firmware.

Two floating refs, not one
--------------------------
`config/west.yml` pinned zmk to the branch `v0.3-branch+dya`. Pinning it to a
SHA is necessary but NOT sufficient: `zmk/app/west.yml` declares zephyr at the
*branch* `v3.5.0+zmk-fixes` (confirmed refs/heads/, not a tag), and freezing zmk
only freezes the manifest *file* — west still re-resolves that branch name on
every update. So zephyr is now redeclared in config/west.yml, where a top-level
project definition takes precedence over the same name in an imported manifest.

That override must replicate zmk's entry verbatim — clone-depth: 1 plus the
entire import name-blocklist — with only `revision` differing. Verified that
`west update` still resolves correctly through it: same SHAs, all 20 hal module
directories present, and both halves build byte-identically to before the pin
(left 420072 B / 111186 B, right 276908 B / 63660 B).

Pins: zmk 4493783e, zephyr dacab4875.

deps-check
----------
Pinning trades silent auto-updates for explicit ones, so this adds the task that
replaces what is given up. It is the counterpart to `doctor`, looking the
opposite way:

  doctor      — does the WORKSPACE match the manifest?   (drift from the pin)
  deps-check  — has UPSTREAM moved past the manifest?    (updates to the pin)

Each pin carries a `# track: <ref>` comment naming the upstream branch it was
taken from, or `tags` to compare against the newest remote tag. deps-check reads
those, does one `git ls-remote` per project (no fetching, no clones), and reports
what moved plus the steps to take an update.

First run already found two real ones, which is the point:
  - eyelash_sofle          4848e21 -> cad1477 (main)
  - runtime-input-processor zmk-v0.3.0.0 -> zmk-v0.4.0.0
Neither is taken here — bumping the board/shield module or jumping a module
major version deserves its own change and its own build verification.

Implementation note: this task uses a TOML *literal* string ('''), because the
embedded Python needs regex escapes (\s, \S, \d) that a basic string would try
to interpret as TOML escapes.

Docs: CLAUDE.md gets the zephyr-override rule and the warning to mirror upstream
changes to that entry when bumping zmk; README gains "3c. Keeping dependencies
current".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@rdlu rdlu added documentation Improvements or additions to documentation enhancement New feature or request labels Sep 2, 2026
@rdlu rdlu self-assigned this Sep 2, 2026
@rdlu

rdlu commented Sep 2, 2026

Copy link
Copy Markdown
Owner Author

CI verification — the zephyr override works from a clean workspace

My local west update reused an existing workspace, which is weak evidence for the override (clone-depth: 1 against a raw SHA rather than a branch name was the real risk). CI does a fresh west init && west update in a clean container, so it is the actual test.

Run 33678273351 — green, all three targets.

Resolved revisions, parsed from that run's own west output:

zmk     4493783    ← the pin
zephyr  dacab487   ← the override, not the branch tip

Memory, versus the last pre-pin main build (33675542224):

Target Flash RAM
Left 420024 B (identical) 111186 B (identical)
Right 276860 B (identical) 63660 B (identical)
settings_reset 46272 B (identical) 11560 B (identical)

Byte-for-byte identical. The pins resolve to exactly what was already building, so this changes nothing about the firmware — only whether it stays that way. No release or reflash needed.

@rdlu
rdlu merged commit 55ad164 into main Sep 2, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant