Skip to content

feat: add wp-api/speculation scaffold - #56

Open
Adi-ty wants to merge 4 commits into
mainfrom
v1.0.0/task/wp-api-speculation
Open

feat: add wp-api/speculation scaffold#56
Adi-ty wants to merge 4 commits into
mainfrom
v1.0.0/task/wp-api-speculation

Conversation

@Adi-ty

@Adi-ty Adi-ty commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Adds the first wp-api category scaffold (wp-api/speculation) — a template that generates a PSR-4 Registrable customising WordPress core's Speculation Rules API (core since WP 6.8), plus the first use of the schema's previously reserved "wizard_step": "wp-apis" and lockstep docs/SKILL/test updates so the new kind is discovered, validated, and wired end-to-end.

Part of

Part of rtcamp/wp-devtools#61

Changes

  • New scaffold scaffolds/wp-api/speculation/ (scaffold.json + speculation.php.mustache + test.php.mustache).
    • Pins speculative-loading mode/eagerness (inputs; defaults prerender/moderate) via wp_speculation_rules_configuration, returning non-array configs unchanged so speculative loading another filter disabled is never revived.
    • Merges an EXCLUDE_PATHS const (const-only, docblock examples for /cart/-style paths) into wp_speculation_rules_href_exclude_paths, preserving other callers' paths (array_unique + array_values).
    • register_hooks() no-ops on WP < 6.8 (function_exists( 'wp_get_speculation_rules' ) guard).
    • Wires into the same module/anchor as wp/registrable ({{base_path}}/../Modules/Services.php, anchor // scaffold:wp/registrable:classes); PSR-4 namespace/paths discovered from composer.json.
  • New wp-api category documented in docs/authoring-scaffolds.md; first scaffold to use the reserved "wizard_step": "wp-apis".
  • wp-api/speculation added to both copies of the scaffold SKILL (kind table, test checklist, PHPUnit framework row).
  • Integration test in tests/scaffolds/bundled-manifests.test.js pinning render layout, discovered namespace, and wiring-anchor reuse.
  • CHANGELOG.md entry under ## Unreleased.

How I verified

❯ node bin/wp-tooling.js validate wp-api/speculation
ok   wp-api/speculation

Total: 1  valid: 1  invalid: 0

❯ npm run check

> wp-tooling-monorepo@0.0.0 check
> npm run check --workspaces --if-present


> @rtcamp/eslint-config@1.0.0 check
> npm run lint && npm test


> @rtcamp/eslint-config@1.0.0 lint
> eslint index.js tests


> @rtcamp/eslint-config@1.0.0 test
> jest

Test Suites: 50 passed, 50 total
Tests:       693 passed, 693 total
Snapshots:   0 total
Time:        1.256 s, estimated 2 s
Ran all test suites.

Acceptance criteria

Runtime behavior

  • wp-api/speculation registers in the engine: valid per schema, discovered by list, renders with no unresolved placeholders.
  • Generated class is a Registrable, pins configured MODE/EAGERNESS, merges EXCLUDE_PATHS, and no-ops on WP < 6.8.
  • Wiring snippet lands on the // scaffold:wp/registrable:classes anchor — verified to match what wp/module --kind=registrable emits.

Code quality

  • Lint — zero errors (eslint src tests; generated PHP clean under consumer rtCampWP/phpcs.xml.dist)
  • Static analysis — zero errors (no engine code touched; schema-valid)
  • Tests pass — 693/693 Jest, incl. new bundled-manifests case; validate catalogue clean (invalid: 0)

Housekeeping

  • CHANGELOG.md entry under ## Unreleased

Reviewer notes

  • follow-up: setting "lens": "performance" on the manifest would make the skill run the performance lens after tests go green; omitted since the skill's kind fallback already covers it.

Adi-ty added 2 commits August 18, 2026 10:38
First scaffold in the new wp-api category and the first to use the reserved "wizard_step": "wp-apis". Generates a Registrable that pins. Generates a Registrable that pins speculative-loading MODE/EAGERNESS via wp_speculation_rules_configuration and merges EXCLUDE_PATHS into wp_speculation_rules_href_exclude_paths, no-op guarded on WP < 6.8; wires into the wp/registrable module/anchor.
@Adi-ty
Adi-ty marked this pull request as ready for review August 18, 2026 05:26
Copilot AI balanced review requested due to automatic review settings August 18, 2026 05:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds the first wp-api scaffold for configuring WordPress Speculation Rules.

Changes:

  • Adds the speculation scaffold and PHPUnit template.
  • Integrates discovery, PSR-4 layout, and Registrable wiring.
  • Updates tests, skills, documentation, and changelog.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/scaffolds/bundled-manifests.test.js Tests scaffold discovery and wiring.
skills/scaffold/SKILL.md Documents scaffold usage and testing.
scaffolds/wp-api/speculation/templates/test.php.mustache Generates PHPUnit coverage.
scaffolds/wp-api/speculation/templates/speculation.php.mustache Generates the Speculation Rules service.
scaffolds/wp-api/speculation/scaffold.json Defines inputs, outputs, and wiring.
scaffolds/setup/claude-skills/templates/scaffold-SKILL.md Updates the generated skill documentation.
docs/authoring-scaffolds.md Documents the wp-api category.
CHANGELOG.md Records the new scaffold.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread node-packages/wp-tooling/scaffolds/wp-api/speculation/scaffold.json Outdated
Comment thread node-packages/wp-tooling/scaffolds/wp-api/speculation/scaffold.json Outdated
Comment thread node-packages/wp-tooling/scaffolds/wp-api/speculation/scaffold.json Outdated
Copilot AI review requested due to automatic review settings August 18, 2026 06:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

node-packages/wp-tooling/scaffolds/wp-api/speculation/scaffold.json:46

  • The mode and eagerness inputs accept arbitrary strings, even though both are closed WordPress enums. resolveInputs() performs no value validation, so a typo such as --mode=prerendering generates a constant that core silently replaces with its default and a generated PHPUnit test that is guaranteed to fail; quotes can also make the generated PHP invalid. Add declarative allowed-values support and reject invalid supplied values before rendering.
			"key": "mode",
			"description": "Speculative loading mode written into the MODE constant. One of 'prefetch' (fetch the document early) or 'prerender' (render it in a hidden tab). 'auto' hands the choice back to core, which resolves it to 'prefetch'.",
			"default": "prerender"

node-packages/wp-tooling/tests/scaffolds/bundled-manifests.test.js:108

  • This does not actually render either new Mustache template: ScaffoldRegistry.execute() skips reading and rendering file/test bodies when dryRun is true (registry.js:378-380 and 419-421). Consequently malformed PHP or an unresolved placeholder in either new template would not fail this integration test despite its stated render coverage. Execute non-dry-run against the temporary directory so template rendering is exercised.
			{ dryRun: true, cwd: target }

Comment thread node-packages/wp-tooling/scaffolds/wp-api/speculation/scaffold.json
Copilot AI review requested due to automatic review settings August 18, 2026 08:17

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (6)

node-packages/wp-tooling/scaffolds/wp-api/speculation/scaffold.json:51

  • eagerness likewise accepts any supplied string, while WordPress only supports auto, conservative, moderate, or eager. Invalid input therefore generates a scaffold that does not apply the requested setting and whose generated PHPUnit test fails. Add and enforce a closed set of allowed values.
			"key": "eagerness",
			"description": "How keenly the browser acts on the rules, written into the EAGERNESS constant. One of 'conservative' (on pointer/touch down), 'moderate' (on hover, this scaffold's default) or 'eager' (as soon as the link is known). 'auto' hands the choice back to core, which resolves it to 'conservative'.",
			"default": "moderate"

node-packages/wp-tooling/src/scaffolds/registry.js:885

  • Valid Composer PSR-4 fallback mappings can use an empty prefix ("": "src/"). For that map, the preceding if (!firstKey) returns before this path branch, so base_path incorrectly keeps includes/... instead of following src/.... Distinguish undefined from an empty key for path inputs, preserve the namespace fallback behavior, and cover this mapping in the discovery tests.
			if (isPathInput(decl.key)) {
				const def =
					typeof decl.default === 'string' ? decl.default : '';
				return graftPath(map[firstKey], def);

node-packages/wp-tooling/scaffolds/wp-api/speculation/scaffold.json:46

  • mode is unrestricted even though it is emitted directly into a PHP constant and WordPress accepts only auto, prefetch, or prerender. A typo currently scaffolds successfully but core silently ignores the requested mode; a quote can also produce invalid PHP. Add and enforce a closed set of allowed input values before rendering.

This issue also appears on line 49 of the same file.

			"key": "mode",
			"description": "Speculative loading mode written into the MODE constant. One of 'prefetch' (fetch the document early) or 'prerender' (render it in a hidden tab). 'auto' hands the choice back to core, which resolves it to 'prefetch'.",
			"default": "prerender"

node-packages/wp-tooling/skills/scaffold/SKILL.md:79

  • This path is not always includes/Services/ anymore: the new PSR-4 directory discovery intentionally renders inc/Services/ or src/Services/ for those project roots. Update the skill table to describe the discovered root directory (and the other affected rows), otherwise the scaffold guidance contradicts the engine and the new integration test.
| `wp-api/speculation` | `includes/Services/` | `<Root>\Services` | `tests/Services/` | `<Root>\Tests\Services` | `<Root>\Modules\Services` |

node-packages/wp-tooling/scaffolds/setup/claude-skills/templates/scaffold-SKILL.md:79

  • This generated skill copy also hard-codes includes/Services/, although the changed resolver writes under the consuming project's PSR-4 directory (inc/Services/, src/Services/, etc.). Introduce a root-directory placeholder and update the affected table rows so generated guidance matches actual scaffold output.
| `wp-api/speculation` | `includes/Services/` | `<Root>\Services` | `tests/Services/` | `<Root>\Tests\Services` | `<Root>\Modules\Services` |

node-packages/wp-tooling/docs/authoring-scaffolds.md:267

  • Adding the new top-level wp-api/ category leaves the package directory guide stale: node-packages/wp-tooling/AGENTS.md:42 still states that scaffolds/ contains only ci/, lint/, setup/, and wp/. Update that contributor-facing layout alongside this category documentation.
`wp` holds the framework-shaped kinds (a CPT, a REST controller, a CLI command). `wp-api` holds scaffolds that customise a **modern WordPress core API** — code whose shape is dictated by core's own hooks and which must be guarded against the WordPress version that introduced them (`wp-api/speculation`, Speculation Rules, WP 6.8). Those pair with `"wizard_step": "wp-apis"`.

@Adi-ty
Adi-ty requested a review from AnuragVasanwala August 19, 2026 09:25
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.

2 participants