Skip to content

docs(web/blog): Anatomy of a Wheels Package - #3024

Merged
bpamiri merged 2 commits into
developfrom
peter/blog-anatomy-of-a-wheels-package
Jun 11, 2026
Merged

bpamiri merged 2 commits into
developfrom
peter/blog-anatomy-of-a-wheels-package

Conversation

@bpamiri

@bpamiri bpamiri commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Publishes "Anatomy of a Wheels Package".

Opened automatically by wheels-publishing-admin on initial publish.

@github-actions github-actions Bot added the docs label Jun 11, 2026

@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 publishes the "Anatomy of a Wheels Package" blog post (web/content/blog/posts/anatomy-of-a-wheels-package.md, 297 lines, docs-only). The technical content is unusually accurate — I verified every load-bearing claim against vendor/wheels/PackageLoader.cfc, ModuleGraph.cfc, SemVer.cfc, ServiceProviderInterface.cfc, cli/lucli/services/packages/Installer.cfc, and the v4 packages guide, and found no factual errors. However, the front matter contains a malformed categories value that will render a literal [] label on the published page, so the verdict is request changes. One fix, plus two minor notes.

Correctness

1. categories front matter is a one-element array containing the literal string "[]" — renders as a visible [] label on the published page. (web/content/blog/posts/anatomy-of-a-wheels-package.md, lines 12–13)

categories:
  - '[]'

Every sibling post uses an empty YAML array — e.g. skip-the-plugin-rate-limited-api.md and background-jobs-without-redis.md both have categories: []. As written here, YAML parses this to ["[]"], which passes the blog's Zod schema (z.array(z.string()) in web/sites/blog/src/content.config.ts:16) and then hits the eyebrow rendering in web/sites/blog/src/layouts/PostLayout.astro:13:

const eyebrow = data.categories && data.categories.length > 0 ? data.categories[0] : null;

So the live post will display the literal text [] as its category eyebrow. Fix:

categories: []

This looks like a serialization bug in the wheels-publishing-admin pipeline (stringifying an empty array before emitting YAML) — worth checking the publisher so the next post doesn't ship the same defect.

Conventions

2. Code-fence title="..." annotations are silently dropped by the blog renderer. (lines 62, 76, 91, 122, 159, 202, 217, 270)

The post uses fence meta like json title="vendor/wheels-greeter/package.json". The blog site is plain Astro with default Shiki highlighting — web/sites/blog/package.json has no astro-expressive-code (or any markdown plugin) dependency, and web/sites/blog/astro.config.mjs has no markdown config. Default Shiki ignores fence meta, so all eight title annotations will be dropped at render time. Nothing breaks, but the prose leans on these as file-path labels (e.g. distinguishing the three different WheelsGreeter.cfc variants at lines 76, 122, and 217). No existing blog post uses fence titles — that convention exists only in the guides site (.mdx on a different stack). Suggest either removing the title= meta or moving the path into the snippet as a comment / preceding prose so readers keep the context.

Commits

  • The single commit 3167155da docs(web/blog): Anatomy of a Wheels Package is a valid conventional-commit header (type docs, 44 chars, not ALL-CAPS), and the PR title matches — the squash-merge gate passes.
  • Minor: the commit has no Signed-off-by trailer. DCO sign-off is project policy per CONTRIBUTING.md (not a CI check, and prior publishing-admin blog posts such as #2825 merged without one, so flagging as a note rather than a blocker). If the publishing pipeline can pass -s, that would align these automated commits with policy.

Fact-check summary (no action needed)

For the record, the claims I verified as accurate against the code at this SHA:

  • Discovery skips vendor/wheels/ and dot-prefixed dirs; per-package error isolation with failedPackages (PackageLoader.cfc $discoverManifests, $discover).
  • Entry-CFC convention: dir-name match, fallback to first .cfc ($instantiatePackage, lines 601–614).
  • Mixin allowlist string matches exactly (line 66); default is "none" when provides.mixins is absent (line 365); unknown targets throw Wheels.PackageInvalidMixinTarget naming the valid set (lines 1058–1064).
  • Per-method mixin metadata override, including the validate-before-mutate pre-pass so a typo on method N never leaves methods 1..N−1 registered ($collectMixins, lines 734–745).
  • requires / replaces / suggests semantics, "Required package not found" wording, cycle exclusion (ModuleGraph.cfc lines 101–156, 203, 249–257); semver ^/~/ranges via wheels.SemVer.satisfiesAll() (SemVer.cfc lines 90–103).
  • Alias derivation incl. the single-segment LCase() caveat ($deriveMapping, line 1115), the [A-Za-z_][A-Za-z0-9_]* override regex with empty-string-fails behavior (lines 1096–1104), and "Duplicate package mapping alias" rollback of the second claimant (lines 1160–1168, $rollbackPackage).
  • register/boot two-phase lifecycle and the lifecycle-hook exclusion list init, onPluginLoad, onPluginActivate, register, boot (line 727); getPackageMappings() / getFailedPackages() / getMixinCollisions() getters and the provides.overrides acknowledged-collision behavior; application.wheels.PackageLoaderObj path (Global.cfc:3400).
  • CLI: add (not install, which LuCLI's extension installer intercepts — PackagesMainCli.cfc:14), sha256 tarball verification with hard abort (Installer.cfc), wheels browser install → setup rename in #2345 (Module.cfc:2523).
  • The "docs drift fixed" claims check out: the v4 packages guide (web/sites/guides/src/content/docs/v4-0-0/digging-deeper/packages.mdx:101,105) now documents requires and the hard-skip wheelsVersion behavior in the words the post describes.
  • The internal link target /posts/skip-the-plugin-rate-limited-api/ exists.

No changelog fragment is required (docs-type blog post, not a user-facing fix/feat). No tests apply. No security concerns.

Once the categories front matter is fixed, this is ready to merge.

Review follow-ups: categories was a one-element array holding the literal
string '[]' (publishing-admin import artifact, now fixed at the source);
the title="..." fence annotations are dropped by the blog's Shiki renderer,
so the file-path labels moved into the preceding prose per the existing
live-post convention.

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

bpamiri commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator Author

Both findings addressed in d310db1:

  1. categories frontmatter — fixed here and at the source: the publishing admin's legacy import had stored the literal string [] in the categories column for the three imported drafts; the db rows are cleaned (the exporter emits a proper categories: [] for empty input — verified in this commit), so the two scheduled follow-up posts in this series won't ship the same defect.
  2. fence titles — all 8 title="..." annotations moved into the preceding prose per the live-post convention (the three WheelsGreeter.cfc variants each now name file + iteration in the prose). The two scheduled posts got the same treatment (4 + 2 occurrences).

Also took the DCO note: this follow-up commit is signed off; adding -s to the publishing pipeline's commits is on the Phase 2 backlog.

🤖 Generated with Claude Code

@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 publishes the blog post "Anatomy of a Wheels Package" (one new file, web/content/blog/posts/anatomy-of-a-wheels-package.md). Because the post makes many specific claims about framework internals, this review is primarily a fact-check against the code — and the post passes it: every load-bearing claim I checked is accurate against vendor/wheels/PackageLoader.cfc, ModuleGraph.cfc, and the CLI installer. Verdict: comment — content is clean; one commit-hygiene item (missing DCO sign-off on the initial commit) should be fixed before merge.

Correctness

No findings. Claims verified against the code, including:

  • Mixin allowlist (application,dispatch,controller,mapper,model,base,sqlserver,mysql,postgresql,h2,test) matches vendor/wheels/PackageLoader.cfc:66 verbatim; global/none special values match $validateMixinTargets (PackageLoader.cfc:1050).
  • Default of none when provides.mixins is absent — PackageLoader.cfc:364-372.
  • Wheels.PackageInvalidMixinTarget thrown for typos/unsupported targets, naming the bad value and listing the valid set — PackageLoader.cfc:1058-1064.
  • Per-method mixin metadata overrides read via GetMetadata() (PackageLoader.cfc:756-759), with the validation pre-pass running before any mixin-table mutation exactly as the post describes (PackageLoader.cfc:730-745).
  • Lifecycle hooks excluded from mixin collection: init,onPluginLoad,onPluginActivate,register,boot — PackageLoader.cfc:727.
  • Entry-CFC convention (dir-name match, fallback to first .cfc) — PackageLoader.cfc:601-614.
  • Alias derivation (first segment LCase'd, wheels-i18n → wheelsI18n, identifier regex, explicit-but-invalid mapping fails rather than falling back) — $deriveMapping, PackageLoader.cfc:1091-1130. Duplicate-alias failure names both claimants and rolls the second package back — PackageLoader.cfc:1160-1168, $rollbackPackage.
  • requires / replaces / suggests semantics, including "suggested package loads first" (soft edge sugDir → dirName in ModuleGraph.cfc), "Required package not found" (ModuleGraph.cfc:203), cycle exclusion with members named (ModuleGraph.cfc:82-91), and SemVer.satisfiesAll() used for both dependency constraints and wheelsVersion (ModuleGraph.cfc:150,235; PackageLoader.cfc:1400).
  • getFailedPackages() / getMixinCollisions() getters and the provides.overrides acknowledged-but-still-recorded behavior — PackageLoader.cfc:129-142,810-822.
  • CLI sha256 verification ("Mismatch = hard abort") — cli/lucli/services/packages/Installer.cfc:8,62-93.
  • The "docs drift fixed" claims check out: the guide (web/sites/guides/src/content/docs/v4-0-0/digging-deeper/packages.mdx:91,101,277) and CLAUDE.md now document requires and the hard wheelsVersion skip in the terms the post describes.

Conventions

No findings. Frontmatter (quoted ISO publishedAt/updatedAt, categories: [], coverImage: null, >- excerpt) matches sibling posts exactly (skip-the-plugin-rate-limited-api.md, background-jobs-without-redis.md). The internal link target /posts/skip-the-plugin-rate-limited-api/ exists. The follow-up commit already addressed the categories import artifact and moved fence titles into prose per the live-post convention.

Commits

  • Missing DCO sign-off on 3167155da (docs(web/blog): Anatomy of a Wheels Package). The commit has no Signed-off-by: trailer; the follow-up d310db130 is properly signed. Per CONTRIBUTING.md § DCO this is project policy verified at review time (there is no CI check for it). Fix before merge with git rebase --signoff develop (or an amend + force-push of the first commit). Both commit headers and the PR title are valid conventional-commit headers (docs(web/blog): …, ≤ 100 chars), so commitlint is clean.

Tests / Docs / Security

Docs-only blog content — no tests required, no changelog fragment required (not a user-facing fix/feat), no security surface. Nothing flagged.

@bpamiri
bpamiri merged commit 55d1999 into develop Jun 11, 2026
13 checks passed
@bpamiri
bpamiri deleted the peter/blog-anatomy-of-a-wheels-package branch June 11, 2026 18:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant