Skip to content

refactor(docs): let compose.yaml be the only place an image version appears - #157

Merged
Gerrrt merged 1 commit into
mainfrom
claude/self-hosted-home-apps-w6a3u0
Aug 26, 2026
Merged

refactor(docs): let compose.yaml be the only place an image version appears#157
Gerrrt merged 1 commit into
mainfrom
claude/self-hosted-home-apps-w6a3u0

Conversation

@Gerrrt

@Gerrrt Gerrrt commented Aug 26, 2026

Copy link
Copy Markdown
Owner

Follow-up to #155, taking the alternative its "Known consequence" section named. Refs #73.

What changed

The service table in stacks/observability/README.md now names images without versions, and assertion 6 of check_docs.py flips from "a version quoted in prose must match compose.yaml" to "a version must not appear in prose at all".

-| `prometheus` | `prom/prometheus:v3.14.0` | 9090 | Metrics store, remote-write receiver, rule evaluation |
+| `prometheus` | `prom/prometheus` | 9090 | Metrics store, remote-write receiver, rule evaluation |

Why

#155 kept the documents honest but kept the duplication, and the duplication is the actual defect. Two problems with matching:

  1. It puts the drift on a timer rather than removing it. Dependabot edits only compose.yaml. A version written anywhere else is stale from the next bump onward — which is precisely how all six in this table became stacks/observability/README.md lists six stale image versions, and CI does not check Markdown #73.
  2. It would have made every Dependabot PR red until someone hand-edited a Markdown table. A check that reliably fails for a known, boring reason is the failure mode this repository already diagnosed for .gitleaksignore: "a CI job that is permanently red for a known reason gets ignored."

ci.yml already reached this conclusion for other file types:

Image versions are NOT duplicated here. They are resolved from compose.yaml at run time by scripts/image-for.sh, because Dependabot only updates compose.yaml — hardcoded copies went stale silently and CI ended up validating v3.1.0 configs against a stack running v3.13.2.

and enforces it with a grep over --include='*.sh' --include='*.yml' --include='Makefile'. Markdown is not in that list, which is how the six survived. This is that existing rule, extended to prose — not a new policy.

What the check now rejects

Naming an image is fine; naming its version is not. `prom/prometheus` passes, `prom/prometheus:v3.14.0` does not. It only fires for repositories compose.yaml actually pins, so an OS version in the hardware table or an untagged registry path is untouched.

The stack README gains a note saying where versions live and that docker compose images prints what is running, so a reader is not left wondering.

Blast radius

  • No change to network segmentation or firewall rules
  • No new port published to a VLAN that could not already reach the service
  • No credential added outside secrets/*.sops.yaml

Documentation and a build-time check. Nothing deployed, no image or service changed — compose.yaml is untouched.

Verification

Mutation-tested, and deliberately with the case the old check could not catch: reintroducing `grafana/loki:3.7.6` — the current, correct pin, which #155's matching check accepted —

$ python3 scripts/check_docs.py
  stacks/observability/README.md:13 pins grafana/loki:3.7.6; only compose.yaml may carry a version — drop the tag and write `grafana/loki`
  ^ image versions in prose (compose.yaml owns them)

1 disagreement(s) between the documents and the configs

Clean tree:

$ python3 scripts/check_docs.py
docs OK — 35 Prometheus + 13 Loki rules, 5 dashboards, 84 panels, 6 assertions
  • make validate passes — not run in full. No docker, promtool, amtool, alloy or gitleaks here, so those sections would have skipped, and skipped checks prove nothing. What ran clean: check_docs.py, markdownlint-cli2, yamllint --strict. CI is the authority on the rest.
  • Deployed to the lab and confirmed working — n/a, nothing deployable changed
  • Docs updated — the service table, and the "Image tags are pinned" note now explains why versions are not repeated

🤖 Generated with Claude Code

https://claude.ai/code/session_01W1QX12EJLwMfRAWsbpfRJz


Generated by Claude Code

…ppears

Assertion 6 of check_docs.py asserted that a version quoted in prose
*matched* compose.yaml. That kept the documents honest but kept the
duplication, and the duplication is the defect: Dependabot edits only
compose.yaml, so a version written anywhere else is stale from the next
bump onward, and the matching check would have turned every Dependabot
PR red until someone hand-edited a table.

ci.yml already refuses duplicated pins in shell, YAML and the Makefile —
"Image versions are NOT duplicated here ... hardcoded copies went stale
silently" — but its grep does not cover Markdown, which is exactly how
the six in the stack README survived to become #73.

So: drop the versions from the service table, keep the image names, and
flip the assertion from "must match" to "must not appear". A version pin
reappearing in prose now fails the build even when the version is
correct, which is the case the old check could not catch.

Mutation-tested: reintroducing `grafana/loki:3.7.6` — the *current*
pin, which the previous check accepted — now fails with
"only compose.yaml may carry a version".

Refs #73

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W1QX12EJLwMfRAWsbpfRJz
@Gerrrt
Gerrrt merged commit a8fa16d into main Aug 26, 2026
0 of 3 checks passed
@Gerrrt
Gerrrt deleted the claude/self-hosted-home-apps-w6a3u0 branch August 26, 2026 16:40
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.

2 participants