Repository navigation
Close the v2 re-audit's template findings - #20
Merged
Merged
Conversation
Three paths of a partial deploy escaped the catches the template documents. uninstall.php called the framework's Uninstaller after its try, so a build missing the engine fataled the uninstall request. dws_tpl_deactivate() built the composition root without the catch dws_tpl_boot() has, so a deactivation on such a build fataled too. functions.php added its hooks before the includes loop, so an include that threw still left the boot and deactivation hooked to a plugin that had not loaded. uninstall.php checks for the engine inside its try, the deactivation reports a build error as the boot does, and the hooks are added after the includes. Rows run each case in its own request, as a missing blocks manifest already gated, which no row covered. Assisted-by: Claude Code:claude-opus-5-5
The Message field took the translated greeting as its default, so the first save of the tab stored it in the language of the admin who saved, and every customer then read that language. includes/migrations.php already keeps translated defaults out of the database for this reason; the field put one back. The field's default is empty and its placeholder shows the translated greeting, and the string reader reads an empty value of an option with a translated default as that default, so an untouched field keeps following the site's language. A cleared Message therefore greets with the default instead of printing nothing. Rows render the placeholder, save the untouched field and read the empty value. Assisted-by: Claude Code:claude-opus-5-5
The fill-in refused only the characters that break the single-quoted
PHP and JavaScript strings, but the display name also lands in the
example block's JSX text, where <, >, { and } break the build. The
Quality rehearsal never built or type-checked the filled-in scripts, so
such a name passed it and the generated plugin failed its first build.
The fill-in refuses <, >, { and } as well, and the rehearsal installs
the filled-in plugin's npm packages, builds it and runs its type lint.
Assisted-by: Claude Code:claude-opus-5-5
lint:types runs tsc over the blocks, assets and end-to-end specs, and the specs read Node's types, but neither typescript nor @types/node was declared: both arrived through @wordpress/scripts, so a change in its tree could swap the compiler's major or drop the types without a change here. Both are declared at the versions the lock already resolves, so the lock moves only its root entries. Assisted-by: Claude Code:claude-opus-5-5
The two settings recipes declared their limit field without a default, so a fresh settings page rendered it empty instead of at the default the recipe's constant holds, and the recurring-jobs recipe read its repair timestamp with a raw filter_var() on get_option(), which AGENTS.md reserves to the typed readers. Both number fields take the default from DWS_TPL_SETTING_DEFAULTS, and the repair gate reads through dws_tpl_get_int_option(). Assisted-by: Claude Code:claude-opus-5-5
Several documents described a template that no longer exists or overstated what it checks. CONTRIBUTING's release steps used arrows and never set the entry file's Version header, which the release refuses to tag without. The issue templates offered a Plugin singleton and a WelcomeNotice the template no longer has. The README listed safeguards where the template ships an empty slot. The entry's Description differed from composer.json's sentence, and the scaffold's TODO left package.json's description out. SECURITY.md said the audit fails on any npm advisory, though it audits only runtime dependencies, of which there are none. Convention 5 implied an absent boolean reads its default, though FILTER_VALIDATE_BOOL reads '' as false. The tests README said Unit runs before the WordPress matrix, which does not wait for it. Each now states what the template does. Assisted-by: Claude Code:claude-opus-5-5
The fill-in swaps the plugin's name and slug into Prettier-formatted TSX. A name or slug shorter than the template's own leaves lines that Prettier would now join, so a plugin generated as "Acme Orders" failed lint:scripts on its first Quality run, while a long name passed, and the rehearsal ran no script lint to notice. After the sweep, the fill-in installs the plugin's npm packages with install scripts off, since its job holds a token that can push, and formats the JS and TS files lint:scripts covers with wp-scripts format. Both the Fill in scaffold workflow and the rehearsal set up Node before the fill-in, and the rehearsal runs lint:scripts with the build and type lint. A short and a long name each pass all three, and formatting changes only the two lines the shorter name shortened. Assisted-by: Claude Code:claude-opus-5-5
The workflows, package.json and the locks pinned configs at 9f64dc7, before configs merged its re-audit follow-ups and the release's tool lock. The template's own release still took WP-CLI from setup-php and checked neither the plugin's own PHP floor nor phpunit.dist.xml. Every workflow ref, the npm dependency and both locks move to 3cbd985. The release now installs its WP-CLI commands from configs' php/release lock, which the template's development install provides, since it requires configs under require-dev; no reusable workflow's inputs change, and each lock changes only the configs entry. Assisted-by: Claude Code:claude-opus-5-5
The template's .distignore excluded README.md but not README.scaffold.md, the README a generated plugin starts from, so the template's own release archive shipped a file that describes filling in a plugin. .distignore excludes README.scaffold.md, and the fill-in drops that line when it moves the file to README.md, which .distignore already excludes, so a generated plugin keeps no exclusion for a file it lacks. Assisted-by: Claude Code:claude-opus-5-5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes from the v2 re-audit:
three partial-deploy paths escaped the plugin's build-error handling;
the greeting's translated default was saved in the saving admin's language;
the scaffold accepted names that break the block's JSX and never built the filled-in scripts, and a plugin generated with a short name failed its first
lint:scripts;TypeScript and the Node types were undeclared;
two recipes lacked a default or a typed read;
several documents described what the template no longer ships;
the template's own release zip shipped
README.scaffold.md;the configs pins lagged behind configs' trunk.
Partial deploys:
uninstall.phpcalled the uninstall engine after its try, so a build missing the engine fataled the uninstall request; it now checks for the engine inside the try.dws_tpl_deactivate()reports a composition root that cannot be built, asdws_tpl_boot()does.functions.phpadds its hooks after loadingincludes/, so an include that throws leaves nothing hooked.Greeting: the Message field's default is empty and its placeholder shows the translated greeting.
dws_tpl_get_string_option()reads an empty value of an option with a translated default as that default, so an untouched field follows the site's language.includes/migrations.phpalready keeps translated defaults out of the database for this reason.Scaffold:
<,>,{and}, which land in the example block's JSX;lint:scriptscovers. A name shorter than the template's own leaves lines that Prettier joins, so "Acme Orders" had failedlint:scripts;fill-in-scaffold.ymland the Scaffold rehearsal set up Node before the fill-in, and the rehearsal builds the filled-in plugin and runslint:scriptsandlint:types.TypeScript:
typescriptand@types/node, whichlint:typesand the end-to-end specs need, are declared at the versions the lock already resolved.Recipes: both settings recipes' limit fields take their default from
DWS_TPL_SETTING_DEFAULTS, and the recurring-jobs recipe reads its repair timestamp throughdws_tpl_get_int_option().Prose: these now match what the template ships:
Version:header;composer.json's sentence;Release zip:
.distignoreexcludesREADME.scaffold.md, and the fill-in drops that line when it moves the file toREADME.md.Configs pins: the workflows,
package.jsonand both locks move from9f64dc7to configs3cbd985. The release now installs its WP-CLI commands from configs'php/releaselock, through the template's own development install of configs.Code +26 −13 (5 files), tests +106 −5 (5 files), workflows, issue templates and fill-in +38 −17 (11 files), docs +13 −9 (7 files),
.distignore+1, npm manifest and the two locks +16 −14.Type of change
Checklist
composer changelog:add): none; the v2 rebuild ships as "Initial release."PartialDeployTestruns a missing blocks manifest, an include that throws, a deactivation whose composition root cannot be built, and an uninstall whose engine cannot load, each in its own request;composer quality-checkpasses locallycomposer.json's sentenceBreaking changes for forks
dws_tpl_get_string_option()reads an empty value of an option with a translated default as that default, so a cleared Message greets with the default instead of printing nothing. The feature's toggle turns the greeting off.<,>,{and}in the plugin name.npm ciand the formatter, so a fork's own fill-in workflow must set up Node first.Review points.
finally. A run killed mid-row can leave a.hiddenfile orincludes/zz-throws.phpbehind.Testing.
composer quality-checkpasses: validate, changelog validation, PHPCS on both profiles, PHPStan, Unit 6 and Integration 75.npm run test:e2epasses (3 of 3).lint:scripts,lint:stylesandlint:typesare clean, and so are actionlint, zizmor and shellcheck.Acme <Orders>passes trunk's script, then fails the new build and type-lint steps; this branch's script refuses it.lint:scripts,lint:stylesandlint:types. The formatter changes only the two lines the short name shortened.make-potanddist-archiverun from it. The archive holds no README, and a scratch fill-in drops the.distignoreline and keeps its leftover checks green.