Skip to content

docs(web/guides): align deploy config-reference + architecture with verified CLI behavior - #3097

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

docs(web/guides): align deploy config-reference + architecture with verified CLI behavior#3097
bpamiri merged 2 commits into
developfrom
peter/docs-audit2-deploy-config

Conversation

@bpamiri

@bpamiri bpamiri commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

Guide-behavioral-audit batch 2, work item p1-16-deploy — the deployment/config-reference.mdx and deployment/architecture.mdx slice (claims cfg-01cfg-16, arch-02arch-06). Every correction below describes current CLI behavior, verified live against the released 4.0.3 CLI and develop source, and links the tracking issue for anything broken-but-unfixed — no aspirational behavior is documented.

config-reference.mdx

Correction Evidence Issue
Umbrella aside + per-key flags for every accepted-but-ignored key: boot.*, logging.*, retain_containers, minimum_version, asset_path, require_destination, allow_empty_roles, run_directory, readiness_delay, hooks.path, builder.arch/args/remote, ssh.proxy/keys_only, proxy.forward_headers/buffering, role env:/options:/labels:, accessory files: cfg-04, cfg-06, cfg-08–cfg-14, acc-03 — zero readers outside the Validator allowlist; spot checks (e.g. minimum_version: "99.0.0" passes, retain_containers: 10 still prunes to 5, role env/options absent from docker run) #3088
env: removed the per-role precedence table (machinery doesn't exist); env.secret callout — silently dropped on 4.0.3, hard-fails Wheels.Deploy.EnvSecretUnsupported on develop cfg-07, sec-08 #2956, #3088
proxy: app_port default is 80 (not 3000), init template writes 8080, and deploy/rollback hardcode the proxy target to :3000 ignoring app_port (verified DeployMainCli.cfc:97/148) cfg-09 #3089
ssh: user defaults to root (not the local user, Ssh.cfc:18-20); ~/.ssh/config is not read (sshj doesn't parse OpenSSH client config; known_hosts is honored) cfg-08
servers: every role currently receives the kamal-proxy deploy cutover call, not just web (observed for a job role in dry-run) cfg-04 #2957
Host validation: documented the colon-under-count gap ('::1:22' passes, Validator.cfc:72) cfg-03 #3086
Interpolation: removed the nonexistent "CLI --env overrides" lookup step (no such flag in DeployArgsParser); noted ${VAR} secrets resolve from config/.kamal/secrets (relative to deploy.yml's directory), not the project root arch-04 #3084
Destination overlays: wheels deploy config ignores --destination; pointed readers at details --destination=... --dry-run arch-03, cfg-15 #3085
Validation errors: prefix is the absolute config path (never line-scoped, intro + required-keys wording too); added the fourth invalid <kind> name: class shipped on develop cfg-01, cfg-02, cfg-16 #3008 / #2956

architecture.mdx

Correction Evidence Issue
Byte-compat table: caution aside for the three aspirational rows — audit log never written (record() has no call sites), docker network create kamal never issued, proxy config dir resolves to /home/root for the default root user arch-02 (DEP-6, DEP-5c, DEP-11c) #2957
Interpolation chain: same --env removal + config/.kamal/secrets resolution note arch-04 #3084
wheels deploy init scaffolding renders four templates (deploy.yml, secrets, Dockerfile, dockerignore — verified in cli/lucli/templates/deploy/init/), not two arch-06, fd-01

Verification

  • pnpm verify:docs src/content/docs/v4-0-0/deployment/config-reference.mdx src/content/docs/v4-0-0/deployment/architecture.mdx1 passed, 0 failed, exit 0
  • All cited defaults/hardcodes re-checked against worktree source (Ssh.cfc, Proxy.cfc, Validator.cfc, DeployMainCli.cfc, init templates)

🤖 Generated with Claude Code

bpamiri and others added 2 commits June 12, 2026 02:58
…erified CLI behavior

Guide-behavioral-audit batch 2 (p1-16-deploy, cfg-*/arch-* claims). Both pages
now describe what the released/develop CLI actually does and link the tracking
issues for everything broken-but-unfixed instead of documenting aspirational
behavior.

config-reference.mdx:
- Flag every accepted-but-ignored key (boot, logging, retain_containers,
  minimum_version, asset_path, require_destination, allow_empty_roles,
  run_directory, readiness_delay, hooks.path, builder.arch/args/remote,
  ssh.proxy/keys_only, proxy.forward_headers/buffering, role env/options/
  labels, accessory files) and link #3088.
- env: remove the nonexistent per-role precedence table; env.secret callout
  (dropped on 4.0.3, EnvSecretUnsupported on develop) citing #2956.
- proxy: app_port default is 80, init writes 8080, deploy/rollback hardcode
  the proxy target to :3000 (#3089).
- ssh: user defaults to root; ~/.ssh/config is not read (known_hosts is).
- servers: every role currently gets a kamal-proxy deploy call (#2957);
  host validator colon-count gap (#3086).
- Interpolation: drop the nonexistent CLI --env step; secrets resolve from
  config/.kamal/secrets (#3084). Overlays: config verb ignores --destination
  (#3085). Validation errors: absolute-path prefix, never line-scoped, plus
  the fourth invalid-name class (#3008).

architecture.mdx:
- Annotate aspirational byte-compat rows (audit log never written, kamal
  network never created, /home/root proxy dir) pending #2957.
- Same --env removal + config/.kamal/secrets note (#3084).
- init scaffolding renders four templates, not two.

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

Ruby Kamal v2.4.0 boots kamal-proxy with a named Docker volume
(kamal-proxy-config), not a host home path under /root, so the prior
clause was a factual error. State the named-volume behavior and note
the bind mount diverges from Kamal either way.

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 the two deployment guide pages (config-reference.mdx, architecture.mdx) with what the wheels deploy CLI actually does, flagging every accepted-but-ignored config key and linking tracking issues for known defects. I independently verified every load-bearing factual claim in the diff against the deploy source at this head — all of them check out — and all eight referenced issues/PRs exist with matching titles. Verdict: approve.

Verification performed

Each corrected claim was checked against cli/lucli/services/deploy/ source rather than taken on faith:

Doc claim Evidence
ssh.user defaults to root config/Ssh.cfc:18-20 (variables.raw.user ?: "root")
~/.ssh/config not read; known_hosts honored lib/SshClient.cfc:67 calls loadKnownHosts(); no OpenSSH client-config parsing anywhere in lib/
app_port default 80 / init writes 8080 / proxy target hardcoded :3000 config/Proxy.cfc:27-31, templates/deploy/init/deploy.yml.mustache:14, cli/DeployMainCli.cfc:97 and :148
Every role receives the kamal-proxy deploy cutover DeployMainCli.cfc:92-101 (deploy) and :143-153 (rollback) loop proxy.deploy(role, …) over all roles
Host validator under-counts adjacent colons config/Validator.cfc:72listToArray(host, ":", false, …) drops empty fields, so '::1:22' counts one colon and passes
No CLI --env interpolation step cli/DeployArgsParser.cfc has no --env flag; envOverride is a constructor-injected test shim only (ConfigLoader.cfc:23-26)
Secrets resolve relative to deploy.yml's directory ConfigLoader.cfc:55projectRoot: getDirectoryFromPath(arguments.path)
wheels deploy config ignores --destination; details resolves it DeployMainCli.cfc:40 loads with no destination opt; :217-222 passes it
Validation errors prefixed with absolute path, never line-scoped Validator.cfc $raise() emits #filePath#: #message#; Module.cfc:2179 sets configPath = expandPath(…)
Fourth invalid <kind> name: error class (develop only) Validator.cfc:84-91; shipped in merged PR #3008
env.secret fail-fast on develop commands/Base.cfc:55-67 throws Wheels.Deploy.EnvSecretUnsupported
Role env: / options: / labels: ignored AppCommands.cfc$labelArgs emits exactly the four built-in labels; $envArgs reads only top-level env().clear(); no options flags emitted
builder.arch/args/remote ignored no --platform / --build-arg / remote endpoint in commands/BuilderCommands.cfc
boot / logging / retain_containers / minimum_version / asset_path / require_destination / allow_empty_roles / run_directory / readiness_delay / hooks.path / ssh.proxy / ssh.keys_only / proxy.forward_headers / proxy.buffering / accessory files: ignored each appears only in the Validator.cfc allowlist; accessors (Ssh.proxy(), Ssh.keysOnly(), Accessory.files()) have zero runtime callers
prune keeps 5 unless --keep cli/DeployPruneCli.cfc:30 (opts.keep ?: 5)
Audit log never written; docker network create never issued; proxy config dir /home/root AuditorCommands.record() has no call sites; DockerCommands.create_network() has no callers while --network kamal is used in AppCommands.run; ProxyCommands.cfc:30 builds /home/#ssh().user()#/.config/kamal-proxy
Four init templates cli/lucli/templates/deploy/init/ contains deploy.yml.mustache, secrets.mustache, Dockerfile.mustache, dockerignore.mustache
Healthcheck defaults /up, 30 config/Proxy.cfc:36

All eight cross-references (#3084, #3085, #3086, #3088, #3089, #2956, #2957, PR #3008) exist and their titles match the claims they're cited for.

Docs

No findings. Docs-type change, so no changelog.d/ fragment is required. The internal reference .ai/wheels/deploy.md doesn't cover these config knobs, so nothing there contradicts the corrections. The "Deploy guides" CI job passed, confirming both MDX files build (the new <Aside> blocks compile against the existing Starlight import).

Commits

Single commit a1fa9db62docs(web/guides): align deploy config-reference + architecture with verified CLI behavior (91-char header, valid docs type, DCO Signed-off-by matching the author). Body explains the why per claim. No findings.

One residual the diff takes on the author's stated live verification: the released-4.0.3 behaviors (silently dropped env.secret, minimum_version: "99.0.0" passing) can't be confirmed from this checkout's source, but develop source is consistent with both — the fail-fast was added post-4.0.3 by #3008, and no version gate exists anywhere in the deploy tree.

@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 the two deployment guide pages (config-reference.mdx, architecture.mdx) with verified wheels deploy CLI behavior — flagging every accepted-but-ignored config key, correcting defaults (ssh.user → root, app_port → 80), and documenting known defects with tracking issues. The head adds one commit over the previously approved revision: a single-line factual correction to the byte-compat aside (Ruby Kamal mounts the named volume kamal-proxy-config, not a host home path). I re-verified the load-bearing claims against the CLI source and all of them hold. Verdict: approve.

Verification (claims spot-checked against source at this head)

  • Delta commit (db875fbe1) — the corrected aside line is accurate on both sides: cli/lucli/services/deploy/commands/ProxyCommands.cfc:30 builds --volume /home/<ssh user>/.config/kamal-proxy:..., which resolves to /home/root for the default root user; and Ruby Kamal 2.x boots kamal-proxy with the named volume kamal-proxy-config (its lib/kamal/commands/proxy.rb run command), so "the bind mount diverges from Kamal either way" is the right framing. This fixes a genuine factual error in the previous revision, which claimed Kamal puts the config dir under /root.
  • ssh.user defaults to rootcli/lucli/services/deploy/config/Ssh.cfc:18-20 (variables.raw.user ?: "root").
  • Proxy cutover hardcoded to :3000, issued for every rolecli/lucli/services/deploy/cli/DeployMainCli.cfc:97 and :148 append & ":3000" inside for (var role in cfg.roles()) loops, confirming both the #3089 aside and the #2957 "every role gets kamal-proxy deploy" correction.
  • app_port default 80; init scaffolds 8080cli/lucli/services/deploy/config/Proxy.cfc:8,27-31; cli/lucli/templates/deploy/init/deploy.yml.mustache:14 (app_port: 8080).
  • Healthcheck defaults /up, 30Proxy.cfc:36 ({path: "/up", interval: 1, timeout: 30}).
  • Colon under-count ('::1:22' passes)cli/lucli/services/deploy/config/Validator.cfc:72: listToArray(host, ":", false, ...) drops empty fields between adjacent colons, so the count comes out at 1 and the string slips through (#3086).
  • Fourth validation class on developValidator.cfc:85-88 raises invalid <kind> name: '<name>' (must match [a-zA-Z0-9][a-zA-Z0-9_.-]*).
  • env.secret hard-fails on developcli/lucli/services/deploy/commands/Base.cfc:59 throws Wheels.Deploy.EnvSecretUnsupported.
  • Interpolation chain: no CLI --env leg; secrets resolved beside deploy.ymlenvOverride appears nowhere in cli/lucli/services/deploy/cli/*.cfc (it's a programmatic test shim only, so removing it from user docs is correct), and ConfigLoader.cfc:52 confirms ".kamal/secrets alongside deploy.yml" resolution (#3084).
  • wheels deploy config ignores --destinationDeployMainCli.cfc:39-40 calls loader.load(configPath) with no destination struct, while details() at :217-222 passes it — so the doc's "use details --destination=... --dry-run" workaround is the right pointer (#3085).
  • Aspirational byte-compat rowsrecord( has zero call sites outside its definition in AuditorCommands.cfc; --network kamal is emitted in three command builders but docker network create is never issued anywhere under cli/lucli/services/deploy/ (#2957).
  • Ignored keysretain_containers appears only in the Validator allowlist (Validator.cfc:18), never read by the runtime; hooks are hardcoded to .kamal/hooks (DeployMainCli.cfc:365), so hooks.path is indeed dead (#3088).
  • Four init templatescli/lucli/templates/deploy/init/ contains exactly deploy.yml.mustache, secrets.mustache, Dockerfile.mustache, dockerignore.mustache, matching the corrected Mustache aside and jmustache dependency note.

Conventions / Commits / Docs

  • Both commits conform to commitlint (docs(web/guides): ..., subjects under 100 chars, DCO sign-off matching the author). The delta commit's body explains the why (factual error vs. Kamal v2.4.0 behavior) — good.
  • All literal <...> placeholders in the new prose (<path to deploy.yml>, <container>:3000, <name>) are backtick-fenced, so the MDX compiles; both files already import Aside.
  • Docs-only docs-type PR: no changelog fragment or test spec required.
  • PR body documents pnpm verify:docs passing for both files.

No correctness, convention, cross-engine, or security findings. The previous wheels-bot review approved head a1fa9db6; this head only improves on it by removing an inaccurate claim about Ruby Kamal's proxy config dir.

@bpamiri
bpamiri merged commit f864ee8 into develop Jun 12, 2026
13 checks passed
@bpamiri
bpamiri deleted the peter/docs-audit2-deploy-config 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