Skip to content

Runtime matrix: test the release package, formatter parity, and write routes; add dev write-API Playground - #105

Merged
dknauss merged 2 commits into
mainfrom
claude/keen-tesla-49orwb
Sep 26, 2026
Merged

dknauss merged 2 commits into
mainfrom
claude/keen-tesla-49orwb

Conversation

@dknauss

@dknauss dknauss commented Sep 26, 2026

Copy link
Copy Markdown
Owner

Summary

What changed?

1. The runtime matrix tests what users install.

  • The matrix used to mount the source checkout, which has no vendor/, so citeproc-php was missing in every cell and the formatter never ran on PHP 7.4–8.4.
  • Each cell now runs npm run package:release and mounts the package (WP_BIBLIO_PLUGIN_DIR), with its production-only vendor/.
  • The workflow gains two steps in both jobs: set up PHP 8.3 with Composer, then package the release.

2. New smoke steps in every cell (scripts/runtime-matrix/smoke.sh):

  • Formatter parity (format-styles.php, run with wp eval-file). It formats tests/fixtures/csl-styles/items.json in all nine styles on that cell's PHP version and compares the output byte for byte with the reviewed goldens. Until now, PHPUnit pinned the styles on PHP 8.3 only.

  • Write routes over real HTTP. A test-only mu-plugin enables the routes and an application password authenticates, with WP_ENVIRONMENT_TYPE=local. The step:

    • runs a dry run, whose ETag must equal the read route's;
    • expects 428 without If-Match and 412 with a stale ETag;
    • makes a real write, which must return a new ETag;
    • checks the new entry in the text route (full Chicago form) and on the front end;
    • checks with check-blocks.php that the rewritten block's markup equals save()'s.

    Real HTTP also shows that Authorization, ETag, and If-Match survive both Apache and nginx.

3. A development-only Playground for the write routes (playground/blueprint-write-api.json, not linked from any badge).

  • It boots the main build with the routes enabled, plus a borgesWrite helper in the block editor's browser console (playground/dev/, fetched from main).
  • Every call makes a dry run first. With { commit: true } it writes, sending the dry run's ETag, then reloads the editor so a stale editor can't overwrite the write on save.
  • The blueprint is generated like the others by npm run playground:build, and src/playground-demo.test.js keeps it in sync.

Once merged, open it with: https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/dknauss/Borges/main/playground/blueprint-write-api.json

Docs: README (the matrix section and blueprint maintenance), CLAUDE.md, docs/rest-write-routes.md (a new "Trying it" section), and the CHANGELOG.

Why? To close the gaps named after #104: the formatter and the write routes had no coverage across PHP and WordPress versions, and there was no easy way to try the write routes by hand.

Validation

  • npm run lint:js passes
  • npm run lint:css: no CSS changes
  • npm run lint:i18n: no source strings changed
  • npm run test passes (873)
  • composer test:php (310) and verify-metrics.sh pass
  • Tested locally in Playground (CLI 3.1.40, WordPress trunk), mounting the packaged release rather than the checkout:
    • format-styles.php: styles-ok 180;
    • the smoke script's own HTTP write sequence, extracted verbatim, passes: dry run, 428, 412, commit, text route, front end;
    • check-blocks.php: blocks-ok 1;
    • the dev blueprint's console helper works: list(), the add and patch dry runs, the clear 409 message on an APA reorder, and a committed add. The editor then reopens with every block valid and nothing unsaved.
  • The Docker matrix itself: I couldn't run it here, because Docker Hub rate-limited the mariadb pull and the mirror's CDN is blocked. This PR's CI runs the 3-cell PR subset, and the full 10 cells run on merge.

Checklist

  • Linked issue or explained why none was needed: requested directly (matrix smoke step and dev blueprint).
  • No sensitive details disclosed publicly

🤖 Generated with Claude Code

https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2


Generated by Claude Code

… routes; add dev write-API Playground

The matrix mounted the source checkout, which has no vendor/, so
citeproc-php was absent in every cell and the formatter never ran there.
Each cell now packages the release (npm run package:release) and tests
what users install, then additionally:

- formats tests/fixtures/csl-styles/items.json in all nine styles on that
  PHP version from the package's own vendor/ and compares with the
  reviewed goldens byte for byte (scripts/runtime-matrix/format-styles.php);
- enables the opt-in write routes with a test-only mu-plugin and, over
  real HTTP with an application password, runs a dry run, gets 428
  without If-Match and 412 with a stale ETag, commits a write, checks
  the new entry in the text route and on the front end, and checks the
  rewritten block's markup equals save()'s (check-blocks.php). Real HTTP
  also proves Authorization/ETag/If-Match survive Apache and nginx.

playground/blueprint-write-api.json (development only, unlinked) boots
the main build with the routes enabled and a borgesWrite helper in the
editor console (playground/dev/): each call dry-runs first; { commit:
true } writes with the dry run's ETag and reloads the editor.

Verified locally against the packaged release in Playground: 180/180
style lines match; the smoke script's own HTTP write sequence passes;
check-blocks reports the rewritten block valid; the console helper's
dry runs, 409 message, and committed write work, and the editor reopens
with every block valid.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2
@dknauss
dknauss marked this pull request as ready for review September 26, 2026 19:59
@codecov

codecov Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.20%. Comparing base (685a083) to head (b4968fa).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #105   +/-   ##
=======================================
  Coverage   87.20%   87.20%           
=======================================
  Files          54       54           
  Lines        5847     5847           
  Branches      597      597           
=======================================
  Hits         5099     5099           
  Misses        267      267           
  Partials      481      481           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

The web server keeps running the opcache-cached wp-config.php without
WP_ENVIRONMENT_TYPE for a couple of seconds after wp config set, so
application passwords are ignored and the write requests arrive logged
out (403). Poll an authenticated /wp/v2/users/me until it returns 200,
and fail fast when no application password was created.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2
@dknauss
dknauss merged commit ebef50c into main Sep 26, 2026
16 checks passed
@dknauss
dknauss deleted the claude/keen-tesla-49orwb branch September 26, 2026 20:14
dknauss pushed a commit that referenced this pull request Sep 26, 2026
Full GPL CSL styles and locales (#103), Phase 05 M0-M3 (stable IDs,
review routes and abilities, opt-in citation and block write routes:
#104, #106), the save-markup language fix, reference-manager .bib
fixes, the Playground demo page (#102), and the runtime matrix on the
release package with formatter-parity and write-route checks (#105).

Version bumped in the plugin header, block.json, readme.txt Stable tag,
the POT header, and the package manifests. CHANGELOG [Unreleased] is
dated as 1.7.0; readme.txt gains a user-facing changelog entry, an
Upgrade Notice, and an FAQ note on the opt-in write routes. README
highlights and STATE/ROADMAP move to the 1.7.0 baseline.

Tested up to stays 7.1: WordPress latest is 7.1.2, which CI's runtime
matrix exercises, including formatter parity across all nine styles.

package-release.sh now also prunes .git directories from vendor/. When
Composer falls back from dist to a git clone (as it did in this
sandbox), the ZIP otherwise carried 4 MB of git metadata.

Release checklist gates run locally: lint:js, lint:css, lint:i18n,
npm audit (0), composer audit (none), Jest 873 passed / 2 skipped,
PHPUnit 318 OK (the 4 vendor deprecations already on main), build,
package:release (552,718-byte ZIP). citeproc-php v2.7.1 is current.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2
@dknauss dknauss mentioned this pull request Sep 26, 2026
9 tasks done
dknauss added a commit that referenced this pull request Sep 26, 2026
* chore(release): 1.7.0

Full GPL CSL styles and locales (#103), Phase 05 M0-M3 (stable IDs,
review routes and abilities, opt-in citation and block write routes:
#104, #106), the save-markup language fix, reference-manager .bib
fixes, the Playground demo page (#102), and the runtime matrix on the
release package with formatter-parity and write-route checks (#105).

Version bumped in the plugin header, block.json, readme.txt Stable tag,
the POT header, and the package manifests. CHANGELOG [Unreleased] is
dated as 1.7.0; readme.txt gains a user-facing changelog entry, an
Upgrade Notice, and an FAQ note on the opt-in write routes. README
highlights and STATE/ROADMAP move to the 1.7.0 baseline.

Tested up to stays 7.1: WordPress latest is 7.1.2, which CI's runtime
matrix exercises, including formatter parity across all nine styles.

package-release.sh now also prunes .git directories from vendor/. When
Composer falls back from dist to a git clone (as it did in this
sandbox), the ZIP otherwise carried 4 MB of git metadata.

Release checklist gates run locally: lint:js, lint:css, lint:i18n,
npm audit (0), composer audit (none), Jest 873 passed / 2 skipped,
PHPUnit 318 OK (the 4 vendor deprecations already on main), build,
package:release (552,718-byte ZIP). citeproc-php v2.7.1 is current.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2

* Parse each CSL style once per format request

CiteProc::render() calls init() every time, which builds a new Context,
reads and parses the locale file, and rebuilds the style's object tree:
about 3 ms, against well under 1 ms to render an entry. With one render
per entry (the fix that stopped an "et al." entry from dropping the
next entry's "and"), 50 entries took about 90 ms, against about 8 ms in
1.6.0 with its short stand-in styles.

Bibliography_Builder_Reusable_CiteProc parses once, records every
property of every object in the parsed style tree, and before each later
render restores them, resets the Context's per-render lists, and zeroes
Layout's static cited-item counter. Each entry renders against the state
a fresh parse would give it: 50 entries now take about 25 ms.

The nine style goldens still match byte for byte. A new test formats the
corpus in reverse order, putting the "et al." and APA 21+ entries ahead
of the short author lists, and requires every entry to match its golden
line; with the restore disabled, both the goldens and the new test fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2

* Drop the #[\Override] attribute from the reusable formatter

PHP 7.4 reads an attribute on its own line as a comment (php -l on
7.4 passes, and so does the PHP 7.4 runtime smoke), but Copilot flagged
it as a 7.4 parse error, and compatibility scanners can do the same. It
does nothing at runtime, so drop it, and turn off Psalm's
MissingOverrideAttribute, which cannot apply to a plugin that supports
PHP 7.4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2

---------

Co-authored-by: Claude <noreply@anthropic.com>
dknauss pushed a commit that referenced this pull request Sep 26, 2026
Since #106, all three nginx cells of the full matrix fail at the
settings PATCH with nginx's own "405 Not Allowed": the smoke test sent
REST requests to /?rest_route=, and for a directory request nginx's
index module only hands GET, HEAD, and POST to index.php, so PATCH,
PUT, and DELETE fall through to the static handler. #105's write steps
used only GET and POST, so they passed. Sites are not affected:
WordPress builds plain-permalink REST URLs as index.php?rest_route=,
and pretty permalinks reach index.php through try_files.

Send every smoke REST request to index.php?rest_route= (REST_URL), and
add nginx-php83-wplatest to the pull-request matrix, which had only
Apache cells and so could not catch this before merge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2
dknauss added a commit that referenced this pull request Sep 27, 2026
Since #106, all three nginx cells of the full matrix fail at the
settings PATCH with nginx's own "405 Not Allowed": the smoke test sent
REST requests to /?rest_route=, and for a directory request nginx's
index module only hands GET, HEAD, and POST to index.php, so PATCH,
PUT, and DELETE fall through to the static handler. #105's write steps
used only GET and POST, so they passed. Sites are not affected:
WordPress builds plain-permalink REST URLs as index.php?rest_route=,
and pretty permalinks reach index.php through try_files.

Send every smoke REST request to index.php?rest_route= (REST_URL), and
add nginx-php83-wplatest to the pull-request matrix, which had only
Apache cells and so could not catch this before merge.


Claude-Session: https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2

Co-authored-by: Claude <noreply@anthropic.com>
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