Skip to content

docs(docker): bump README example image tag from 14.8.0 to 17.0.0 - #9016

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-8961-docker-readme-stale-tag
Aug 16, 2026
Merged

docs(docker): bump README example image tag from 14.8.0 to 17.0.0#9016
os-project-manager merged 1 commit into
mainfrom
claude/issue-8961-docker-readme-stale-tag

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#8961

The fix

docker/README.md pinned its three example image references at 14.8.0
while packages/cli/package.json is at 17.0.0 — three majors stale:

  • :32FROM ghcr.io/objectstack-ai/objectstack:14.8.0
  • :43 — the docker run example
  • :65docker build --build-arg OS_CLI_VERSION=14.8.0

All three now read 17.0.0. This is the same defect class PR #8960 fixed in
content/docs/deployment/self-hosting.mdx for #8911; docker/README.md was
outside that card's file surface, hence a separate card and PR.

Why it's a bug and not cosmetic: a reader who copies the FROM line gets a
v14 runtime, then builds with a current v17 CLI. The runtime's
engines.protocol gate refuses that pairing by design ("the safety belt of
the two-axis split"), so the copy-paste path from this README ended in a
boot failure caused by one stale digit.

The convention question (recommendation, not implemented here)

The issue asks for a recommendation on whether these examples should carry a
concrete version at all, versus packages/create-objectstack/src/templates/blank/Dockerfile:26's
:latest approach — not implemented in this PR, per scope instruction.

Recommendation: keep the concrete-version convention (17.0.0, as this
PR and self-hosting.mdx both do), and instead treat create-objectstack's
:latest as the outlier to fix in a follow-up — not the other way around.

  • docker/README.md's own tag table (line 20) says it explicitly: X.Y.Z
    "pin this in production"; latest is scoped there to "quick starts
    only." A concrete-version example is the README teaching its own stated
    best practice by demonstration. Docs that recommend pinning and then show
    :latest in the primary example undercut the advice they just gave.
  • The create-objectstack template Dockerfile already half-agrees: its
    comment right above the FROM line reads "Pin the tag to the
    @objectstack/cli version in your package.json so the runtime matches the
    CLI that built the artifact" — but the FROM line itself uses :latest,
    contradicting its own comment. That's a second, independent defect in that
    file, not a reason to move the other two surfaces toward :latest.
    Filed separately below rather than fixed here (different file surface,
    different readers, and the issue says not to touch it in this PR).
    create-objectstack is scaffolded once per app at npx create-objectstack
    time, so :latest there also means every scaffolded app silently drifts
    to whatever image is newest at each rebuild, unrelated to the CLI version
    actually pinned in the generated package.json — the opposite of what its
    own comment promises.
  • A concrete version's cost (goes stale on every major) is exactly what a
    mechanical guard should absorb, rather than trading it for a convention
    (:latest) that silently breaks the "pin in production" guidance for
    every reader who copies the example as-is.

Mechanical guard (recommendation, not implemented here)

A durable fix, now that this has happened twice: a gate that asserts the
concrete-version docs image tags in docker/README.md and
content/docs/deployment/self-hosting.mdx share packages/cli/package.json's
major (or full version, since both currently pin exact versions) —
scripts/check-docs-image-tag.mjs in the spirit of the existing
scripts/check-*.mjs gate family, run in the same lint/docs workflow.

What it would assert: extract every ghcr.io/objectstack-ai/objectstack:X.Y.Z
and OS_CLI_VERSION=X.Y.Z literal from the two known doc surfaces via
regex, compare against packages/cli/package.json's version, fail listing
file:line + found vs. expected on any mismatch.

How it would be proven capable of failing: revert one occurrence to a stale
version locally, confirm the gate goes red naming that file:line, then
restore and confirm green — the same reverse-verification discipline used
for code gates.

Filed as a separate, unassigned issue (out_of_scope_findings below) rather
than built in this PR, since it's new gate infrastructure beyond the
three-line mechanical fix the card asks for and needs its own review of
false-positive risk (the tag table's own doc text on line 20 contains
X.Y.Z as a pattern, not a literal version, and a naive regex would need to
exclude it).

Verification

  • pnpm check:nul-bytes — green (5947 tracked text files scanned, no raw
    control bytes).
  • node scripts/pm/dispatch-gates.mjs docker/README.md — 0 of 98 discovered
    check families name this path; no gate family fires on this file.
  • Confirmed no remaining 14.8.0 occurrences in docker/README.md.
  • HEAD at time of verification: 5f7a99a92.

skip-changeset applied — docker/README.md is documentation outside
published package source, not user-visible package behavior.

Out of scope, filed separately

  • packages/create-objectstack/src/templates/blank/Dockerfile:26 uses
    :latest while its own adjacent comment instructs pinning to the CLI
    version — a second, independent defect, different file surface, different
    readers. Not touched here per the issue's explicit instruction.
  • A mechanical guard asserting docs image tags track packages/cli's
    version (see above) — new gate infrastructure, filed for PM triage rather
    than built unreviewed in this PR.

Generated by Claude Code


Generated by Claude Code

docker/README.md pinned its FROM, docker run, and OS_CLI_VERSION build-arg
examples at 14.8.0 while packages/cli is at 17.0.0 -- three majors stale.
A reader who copies the FROM line gets a v14 runtime paired with a current
v17-built artifact, and the engines.protocol gate refuses that pairing by
design, so the copy-paste path ended in a boot failure caused by one stale
digit.
Same defect class PR #8960 fixed in content/docs/deployment/self-hosting.mdx
for #8911; this file was outside that card's scope.
Fixes#8961
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011RB4waLuNbdruCo6X9oobm
@vercel

vercelBot commented Aug 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 16, 2026 6:16am

Request Review

@os-project-manageros-project-manager added documentation Improvements or additions to documentation skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed size/xs labels Aug 16, 2026 — with Claude
@os-project-manager
os-project-manager marked this pull request as ready for review August 16, 2026 06:19
@os-project-manager
os-project-manager added this pull request to the merge queueAug 16, 2026
Merged via the queue into main with commit 792524cAug 16, 2026
34 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-8961-docker-readme-stale-tag branch August 16, 2026 06:44
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 17, 2026
…ectstack-ai#9018) (objectstack-ai#9065)
The same "example image tag N majors behind packages/cli" staleness was found
and hand-fixed twice, independently: content/docs/deployment/self-hosting.mdx
(objectstack-ai#8911, PR objectstack-ai#8960) and docker/README.md (objectstack-ai#8961, PR objectstack-ai#9016). Two occurrences of an
identical drift is the threshold both prior cards named as the point where a
mechanical guard beats fixing the third one by hand.
Adds scripts/check-docs-image-tag.mjs (dependency-free, pure filesystem), the
check:docs-image-tag root script, and a step in lint.yml's required ESLint job
-- the job whose REQUIRED_CONTEXTS `carries` field records "the whole check:*
gate family", verified in the ledger rather than recalled.
Three anchored patterns over three explicitly enumerated surfaces: the ghcr
image tag, the OS_CLI_VERSION build arg, and the @objectstack/cli@ npm pin.
Only tags opening with three dot-separated integer groups are compared, which
is what excludes docker/README.md's own X.Y.Z tag-table metavariable. A surface
that yields no concrete pin fails rather than passing, so the enumeration
cannot rot into a silent no-op.
Both target surfaces were repaired within the day, so the live corpus is
guaranteed green and a passing run cannot distinguish a working gate from a
blind one. Every limb therefore carries a positive control in --self-test over
a temp fixture running the real checkSurfaces path, paired with a clean fixture
asserting zero findings, plus a live control proving the X.Y.Z metavariable is
still in docker/README.md and still excluded there.
Claude-Session: https://claude.ai/code/session_011RB4waLuNbdruCo6X9oobm
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs(docker): docker/README.md pins the runtime image at 14.8.0 — three majors stale against packages/cli

2 participants

@os-project-manager@claude