Skip to content

docs(web/guides): align deployment guides with verified wheels deploy behavior (audit batch 2) - #3102

Merged
bpamiri merged 2 commits into
developfrom
peter/docs-audit2-deploy-guides
Jun 12, 2026
Merged

docs(web/guides): align deployment guides with verified wheels deploy behavior (audit batch 2)#3102
bpamiri merged 2 commits into
developfrom
peter/docs-audit2-deploy-guides

Conversation

@bpamiri

@bpamiri bpamiri commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

Docs-fix wave for the guide behavioral audit (batch 2, work item p1-16-deploy — "all other deployment guides"). Every correction below traces to a verified claim in the audit manifest; each broken-but-unfixed behavior is documented as current behavior with the tracking issue cited, never as an aspirational fix.

Sibling scope note: architecture.mdx and config-reference.mdx are handled in a separate PR of this wave. docker-deployment.mdx was checked and contains none of the flagged patterns — no changes needed.

Corrections by file

first-deploy.mdx

secrets.mdx

hooks.mdx

accessories.mdx

vm-deployment.mdx

  • vm-01: wheels dbmigrate latest|downwheels migrate latest|down (no dbmigrate subcommand exists).
  • vm-04: X-Forwarded-Proto aside now states the header is only honored after set(trustProxyHeaders=true) — verified live (header alone → isSecure() false).

observability-and-logging.mdx

migrating-from-kamal.mdx

Verification

  • pnpm verify:docs over all 8 scoped files: 13 tagged blocks, 13 passed, exit 0.
  • All invocation forms verified against the audit's live evidence (wheels CLI 4.0.3 + develop source + Lucee 7 docker harness) and re-checked against current cli/lucli/Module.cfc / DeploySecretsCli.cfc / DeployArgsParser.cfc / RequestId.cfc / rendering.cfc source.

Issue refs: #2674, #2677, #2697, #2956, #2957, #3084, #3087, #3088, #3090.

🤖 Generated with Claude Code

bpamiri and others added 2 commits June 12, 2026 03:03
…oy behavior

Audit batch 2 (p1-16-deploy) corrections across seven deployment guides:
broken invocations replaced with the working flat aliases, env.secret
delivery marked pending (#2956/#2957), setup==deploy orchestration gap
called out (#2957), failure-hook masking documented (#3087), accessory
files:/labels corrected (#3088), and all four broken observability
examples fixed against a live Lucee 7 harness.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Peter Amiri <peter@alurium.com>
… secrets flow

The flow diagram asserted the registry password is fed to docker login
over stdin unconditionally, but that is develop-only behavior (post-#3008).
The released 4.0.3 CLI still inlines it via -p <password>, exposing it in
the remote process table and --dry-run output. Qualify the claim to match
the 4.0.3-vs-develop split the rest of the page already uses.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Peter Amiri <peter@alurium.com>

@wheels-bot wheels-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wheels Bot — Reviewer

TL;DR: This PR aligns seven deployment guides with the verified behavior of the wheels deploy Phase 1 CLI (audit batch 2). I cross-checked every checkable claim in the diff against the CLI and framework source and found zero factual errors — an unusually high bar for a docs wave this size. Verdict: comment (two non-blocking editorial nits below; nothing rises to a change request).

Correctness

All of the following diff claims were verified against source on this head:

Claim in diff Evidence
wheels deploy init creates four files; Dockerfile overwrite refused without --force cli/lucli/services/deploy/cli/DeployMainCli.cfc:334-378 (init_stub)
setup is an alias for deploy (no proxy/accessory boot) DeployMainCli.cfc:162-165 — body is literally return deploy(arguments.opts); with a "Phase 2 will add accessory boot" comment
Rollback version is positional cli/lucli/Module.cfc:2194-2199opts.version = positional[2], throws without it
Flat fetch-secrets / extract-secrets / print-secrets verbs; nested secrets/server intercepted Module.cfc:2397-2417; cli/CLAUDE.md confirms LuCLI reserves nested server/secrets and --version
develop rejects env.secret with Wheels.Deploy.EnvSecretUnsupported cli/lucli/services/deploy/commands/Base.cfc:59; AccessoryCommands.cfc:92 calls $rejectEnvSecrets
Missing secret keys resolve to empty string, no "unresolved secret" error SecretResolver.cfc:45-47 (variables.resolved[arguments.key] ?: "")
Empty registry password fails fast on develop DeployRegistryCli.cfc:49 (DeployRegistryCli.MissingPassword)
Registry password fed over docker login --password-stdin RegistryCommands.cfc:13-26
KAMAL_PERFORMER = git config user.name, $USER fallback; no KAMAL_ROLE/KAMAL_SERVICE set HookCommands.cfc:47-63; repo-wide grep finds no KAMAL_ROLE assignment
Non-zero post-deploy-failure hook exit masks the original deploy error (#3087) DeployMainCli.cfc:113-115 fires the hook inside the deploy catch; $fireHook throws DeployMainCli.HookFailed on non-zero exit (DeployMainCli.cfc:506-507), replacing e
Accessory files: parsed but never delivered (#3088) config/Accessory.cfc:56-58 exposes it; AccessoryCommands.cfc builds run from labels/ports/volumes/env only — no upload
Accessory label is service=<service>-<accessory>; details inspects by container name AccessoryCommands.cfc:7,44-46,68-74
Proxy config dir computed as /home/<user> even for root ProxyCommands.cfc:30 (hardcoded /home/#…user()#/.config/kamal-proxy)
No CLI --env override step in ${VAR} interpolation ConfigLoader.cfc:23-28envOverride is constructor-injection only (tests); no --env flag anywhere in the deploy CLI
.kamal/secrets lookup relative to deploy.yml's directory (#3084) ConfigLoader.cfc:53-58projectRoot: getDirectoryFromPath(arguments.path)
Middleware context has no cgi key vendor/wheels/Dispatch.cfc:420-425 — exactly {params, route, pathInfo, method}
$writeRequestId private-helper pattern for Adobe request-parameter shadowing mirrors the framework's own vendor/wheels/middleware/RequestId.cfc:32-40 verbatim — documented prior art, and private is correct here (middleware is not a mixin, so Cross-Engine Invariant 7 doesn't apply)
renderWith takes status, not statusCode vendor/wheels/controller/rendering.cfc — every render signature declares string status = $statusCode()
queueStats() exists; no wheels jobs status CLI vendor/wheels/Job.cfc:464; no jobs subcommand in Module.cfc (the root CLAUDE.md worker-CLI block is indeed stale — agree with deferring that to #3090, outside this PR's file scope)
No wheels dbmigrate subcommand only a template-comment mention in Module.cfc:3101
trustProxyHeaders gate for X-Forwarded-Proto vendor/wheels/Global.cfc, events/onapplicationstart.cfc, tests/specs/security/TrustProxyHeadersSpec.cfc

One subtlety I checked and chose not to flag: documenting --release= as the flag for redeploy overrides and app details. Current brew/scoop wrappers rewrite --version--release before picocli (header of DeployArgsParser.cfc), so --version can work on a fresh install — but --release is the spelling that works everywhere, and the runtime genuinely reserves --version (cli/CLAUDE.md). The doc's guidance is the safe universal form.

Docs

Two non-blocking nits:

  1. accessories.mdx (env.secret aside) — the aside says the features are "parsed but not implemented," but its siblings in first-deploy.mdx and secrets.mdx also spell out that CLIs built from develop hard-reject env.secret with Wheels.Deploy.EnvSecretUnsupported. That rejection applies to accessories too (AccessoryCommands.cfc:92 calls $rejectEnvSecrets), so a develop-CLI user with an accessory env.secret: block gets an error, not a silent skip. Worth one matching sentence for consistency.

  2. first-deploy.mdx step 1 ("Creates four files") — accurate for a fresh app, but the two generated Docker files behave asymmetrically on conflict: an existing Dockerfile makes init refuse without --force (documented), while an existing .dockerignore is silently preserved (DeployMainCli.cfc:371-378 — "preserved existing .dockerignore"). Optional one-liner; the current text isn't wrong for the guide's fresh-app audience.

Tests

Docs-only PR; no spec changes required. The removal of the {test:cli} tag on the bootstrap block is justified — the corrected command genuinely requires reachable SSH hosts, and the old tag only passed because the broken nested form printed help and exited 0. PR body reports pnpm verify:docs at 13/13 tagged blocks passing.

Commits

Single commit 139d40b0f docs(web/guides): fix deployment guides to match verified wheels deploy behavior — valid type, header well under 100 chars, DCO sign-off present and matching the author. PR title is likewise a valid conventional header for the squash merge.

@wheels-bot wheels-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wheels Bot — Reviewer

TL;DR: Re-review at head 5cb5e08. The delta since the previous review round (139d40b) is a single commit that version-qualifies the docker-login stdin claim in secrets.mdx — and it is exactly right: I verified both sides of the 4.0.3-vs-develop split against source. The rest of the diff is unchanged from the previously reviewed commit, and my independent spot-checks of its load-bearing claims all confirmed. Verdict: comment — no blocking findings; two minor docs nits from the previous round remain open and are repeated below for tracking.

Correctness

The new hunk (secrets.mdx:153) claims develop feeds the registry password over docker login --password-stdin while released 4.0.3 inlines it via -p <password>. Both verified:

  • develop: cli/lucli/services/deploy/commands/RegistryCommands.cfc:20-28 builds docker login <server> -u <user> --password-stdin, with a doc comment explaining the deliberate divergence from Kamal so the password "can't leak through dry-run output, exception summaries, or the remote process table (#2956)".
  • 4.0.3: git show v4.0.3:cli/lucli/services/deploy/commands/RegistryCommands.cfc shows docker("login", reg.server(), "-u", reg.username(), "-p", arguments.opts.password ?: "") — inline, exactly as the doc now states.
  • #3008 is merged (2026-06-11) and is the fix PR; #2956 is the open tracking issue. The "(4.0.4+)" qualifier is consistent with v4.0.3 being the latest tag.

The qualified paragraph also matches the 4.0.3-vs-develop framing the page already uses at lines 14 and 46, so the page reads consistently.

Independent spot-checks of the unchanged bulk (sampling the highest-impact claims):

Doc claim Evidence
Rollback version is positional; --version= intercepted cli/lucli/Module.cfc:2194-2199opts.version = positional[2], throws without it
renderWith argument is status, not statusCode vendor/wheels/controller/rendering.cfc:26,131,205 — every render signature declares string status = $statusCode()
Middleware context has no cgi key vendor/wheels/Dispatch.cfc:420-425 — exactly {params, route, pathInfo, method}
$writeRequestId Adobe-shadowing helper pattern mirrors vendor/wheels/middleware/RequestId.cfc verbatim, including its comment citing CLAUDE.md cross-engine anti-pattern #11
KAMAL_PERFORMER = git config user.name, $USER fallback cli/lucli/services/deploy/commands/HookCommands.cfc:54-63
Flat fetch-secrets/extract-secrets/print-secrets verbs; nested secrets intercepted by the picocli root Module.cfc:2397-2419 — the comment block documents #2697 and the alias rationale
develop rejects env.secret with Wheels.Deploy.EnvSecretUnsupported cli/lucli/services/deploy/commands/Base.cfc:55-59
X-Forwarded-Proto honored only behind set(trustProxyHeaders=true) vendor/wheels/Global.cfc:2390-2392 ($trustProxyHeaders())

No factual errors found.

Docs

Two non-blocking nits carried forward from the previous review round — both still present at this head (only secrets.mdx changed since):

  1. accessories.mdx (env.secret aside, ~line 34) — the aside says accessory env.secret: is "parsed but not implemented," but develop CLIs hard-reject it: AccessoryCommands.cfc:92 calls $rejectEnvSecrets, which throws Wheels.Deploy.EnvSecretUnsupported (Base.cfc:55-59). The sibling asides in first-deploy.mdx and secrets.mdx spell out this 4.0.3-silently-drops vs develop-rejects split; one matching sentence here would make the three asides consistent.
  2. first-deploy.mdx step 1 ("Creates four files") — accurate for a fresh app, but the two Docker files behave asymmetrically on conflict: an existing Dockerfile makes init refuse without --force (documented), while an existing .dockerignore is silently preserved (DeployMainCli.cfc init_stub). Optional one-liner.

Tests

Docs-only; no spec changes required. PR body reports pnpm verify:docs at 13/13 tagged blocks passing across the scoped files.

Commits

Both commits are valid conventional headers (docs(web/guides): …, 81 and 83 chars) with DCO sign-offs matching the author (Signed-off-by: Peter Amiri <peter@alurium.com>). The new commit's body explains the why (4.0.3 process-table exposure vs develop stdin) rather than restating the diff — good.

@bpamiri
bpamiri merged commit 600548e into develop Jun 12, 2026
13 checks passed
@bpamiri
bpamiri deleted the peter/docs-audit2-deploy-guides branch June 12, 2026 11:34
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