Commit Graph
288 Commits
Author SHA1 Message Date
Kydoimosandanthropic/claude-opus-4-8 67017409d7 Drop stale comment about not applying credit at booking
CI / Coding Standards (pull_request) Successful in 29s
CI / Tests (PHP 8.1) (pull_request) Successful in 36s
CI / No Debug Code (pull_request) Successful in 11s
CI / Tests (PHP 8.5) (pull_request) Successful in 36s
CI / Static Analysis (pull_request) Successful in 41s
CI / Tests (PHP 8.2) (pull_request) Successful in 43s
CI / Tests (PHP 8.3) (pull_request) Successful in 43s
CI / Build Plugin Zip (pull_request) Skipped
This change applies credit at booking for scheduled rebooks, so the note
saying the pay-now flow deliberately does not was contradictory.

Co-authored-by: anthropic/claude-opus-4-8
2026-09-17 15:42:38 -03:00
Kydoimosandanthropic/claude-opus-4-8 e7de627752 Apply account credit on same-month rebook, surface credit on student page
CI / Coding Standards (pull_request) Successful in 27s
CI / Tests (PHP 8.2) (pull_request) Successful in 28s
CI / No Debug Code (pull_request) Successful in 9s
CI / Tests (PHP 8.5) (pull_request) Successful in 35s
CI / Tests (PHP 8.1) (pull_request) Successful in 37s
CI / Tests (PHP 8.3) (pull_request) Successful in 43s
CI / Static Analysis (pull_request) Successful in 51s
CI / Build Plugin Zip (pull_request) Skipped
A monthly/weekly lesson booked into a month whose billing date has
already passed is charged at booking time by LessonBooker::settle,
bypassing the daily scan where account credit is otherwise applied. So
rebooking a cancelled paid lesson within the same month charged the
family in full while their cancellation credit sat unused — billed twice
for the same slot.

Apply the payer's credit to that charge-at-booking payment for scheduled
offerings, mirroring the daily scan: a payment fully covered by credit
settles and confirms its lesson. Add PaymentService::findPayment so
settle can re-read the row after applyCredits writes to it.

Also surface the student's total account credit at the top of their
detail page when they hold a balance, so the studio sees it at a glance.

Co-authored-by: anthropic/claude-opus-4-8
2026-09-17 15:39:53 -03:00
thatguygriff d8d842b1ef Merge pull request 'Fix two duplicate-charge bugs in scheduled billing' (#201) from fix/duplicate-payment-due-notice into main
CI / Coding Standards (push) Successful in 16s
CI / No Debug Code (push) Successful in 5s
CI / Tests (PHP 8.5) (push) Successful in 24s
CI / Tests (PHP 8.1) (push) Successful in 40s
CI / Tests (PHP 8.3) (push) Successful in 46s
CI / Static Analysis (push) Successful in 1m2s
CI / Tests (PHP 8.2) (push) Successful in 1m1s
CI / Build Plugin Zip (push) Successful in 15s
Reviewed-on: #201
Reviewed-by: James Griffin-Allwood <[email protected]>
2026-09-17 18:25:18 +00:00
Kydoimosandanthropic/claude-opus-4-8 acda3cda0f Reconcile up-front charges when a class switches to monthly billing
CI / Coding Standards (pull_request) Successful in 25s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.1) (pull_request) Successful in 36s
CI / Tests (PHP 8.2) (pull_request) Successful in 39s
CI / Tests (PHP 8.3) (pull_request) Successful in 51s
CI / Tests (PHP 8.5) (pull_request) Successful in 59s
CI / Static Analysis (pull_request) Successful in 1m3s
CI / Build Plugin Zip (pull_request) Skipped
A student who enrols while a group class is pay-now is charged once at
enrolment, and that charge carries no period_key. When the class is
later switched to monthly, the daily scan — which dedups scheduled
charges by period_key — does not see the up-front charge and bills the
enrolment again for the current month, double-charging students who
had already paid. The differing payer between the two rows (student vs
guardian) was a side effect of guardian links created between the two
charge dates, not the cause.

Switching a group class into monthly now adopts each active enrolment's
up-front charge into the current month (stamping period_key and
due_date) so the scan treats that month as billed and charges from the
next month on. Enrolments with no up-front charge, or already billed
for the month, are left alone; weekly and non-group offerings are not
touched. Wired into both offering-update paths (admin form and REST).

Co-authored-by: anthropic/claude-opus-4-8
2026-09-17 15:07:22 -03:00
Kydoimosandanthropic/claude-opus-4-8 e389e40843 Send each scheduled payment's due notice exactly once
CI / Coding Standards (pull_request) Successful in 28s
CI / Tests (PHP 8.1) (pull_request) Successful in 35s
CI / No Debug Code (pull_request) Successful in 9s
CI / Tests (PHP 8.3) (pull_request) Successful in 44s
CI / Tests (PHP 8.2) (pull_request) Successful in 47s
CI / Tests (PHP 8.5) (pull_request) Successful in 48s
CI / Static Analysis (pull_request) Successful in 52s
CI / Build Plugin Zip (pull_request) Skipped
The daily billing scan runs on request via WP-Cron and can overlap
itself under concurrent traffic. Each run emailed the payments it
created with no record that a notice had gone out, so two overlapping
runs could send a payer two identical "Payment due" emails for one
charge — read by families as being billed twice, though only one row
exists.

Stamp us_payments.notice_sent_at atomically before emailing: the scan
now claims each payment with a conditional UPDATE ... WHERE
notice_sent_at IS NULL and only notices, credits and batches the rows
it won. A competing run finds them claimed and stays quiet, so exactly
one notice is sent regardless of how the scan is triggered. A one-time
backfill stamps existing scheduled rows on upgrade so already-noticed
charges are not re-emailed.

Co-authored-by: anthropic/claude-opus-4-8
2026-09-17 13:19:25 -03:00
thatguygriff 6c92fc35fd Delete directory '.claude'
CI / Coding Standards (push) Successful in 17s
CI / No Debug Code (push) Successful in 5s
CI / Tests (PHP 8.5) (push) Successful in 24s
CI / Tests (PHP 8.2) (push) Successful in 35s
CI / Tests (PHP 8.1) (push) Successful in 51s
CI / Tests (PHP 8.3) (push) Successful in 52s
CI / Static Analysis (push) Successful in 1m2s
CI / Build Plugin Zip (push) Successful in 16s
2026-09-17 00:10:58 +00:00
thatguygriff cd86f6bdeb Merge pull request 'Add AGENTS.md, point CLAUDE.md files at it' (#200) from docs/agent-instructions into main
CI / Coding Standards (push) Successful in 24s
CI / No Debug Code (push) Successful in 8s
CI / Tests (PHP 8.5) (push) Successful in 33s
CI / Static Analysis (push) Successful in 38s
CI / Tests (PHP 8.2) (push) Successful in 36s
CI / Tests (PHP 8.1) (push) Successful in 47s
CI / Tests (PHP 8.3) (push) Successful in 47s
CI / Build Plugin Zip (push) Successful in 12s
Reviewed-on: #200
Reviewed-by: James Griffin-Allwood <[email protected]>
2026-09-16 15:29:58 +00:00
Kydoimosandopencode/muse-spark-1.3-contributor-free 63ee248695 Add AGENTS.md, point CLAUDE.md files at it
CI / Coding Standards (pull_request) Successful in 14s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.1) (pull_request) Successful in 34s
CI / Tests (PHP 8.3) (pull_request) Successful in 43s
CI / Tests (PHP 8.5) (pull_request) Successful in 45s
CI / Tests (PHP 8.2) (pull_request) Successful in 1m0s
CI / Static Analysis (pull_request) Successful in 1m2s
CI / Build Plugin Zip (pull_request) Skipped
Co-authored-by: opencode/muse-spark-1.3-contributor-free
2026-09-16 12:21:55 -03:00
thatguygriff 91eb30b222 Merge pull request 'Sign the automated version bump commit in CI' (#199) from ci/sign-version-bump-commit into main
CI / Coding Standards (push) Successful in 30s
CI / Tests (PHP 8.5) (push) Successful in 27s
CI / Tests (PHP 8.3) (push) Successful in 34s
CI / No Debug Code (push) Successful in 6s
CI / Static Analysis (push) Successful in 38s
CI / Tests (PHP 8.1) (push) Successful in 41s
CI / Tests (PHP 8.2) (push) Successful in 40s
CI / Build Plugin Zip (push) Successful in 23s
Reviewed-on: #199
Reviewed-by: James Griffin-Allwood <[email protected]>
2026-09-05 23:29:51 +00:00
KydoimosandClaude Opus 5 c4b2b5ccff Sign the automated version bump commit in CI
CI / Coding Standards (pull_request) Successful in 23s
CI / Tests (PHP 8.5) (pull_request) Successful in 27s
CI / Tests (PHP 8.2) (pull_request) Successful in 35s
CI / Static Analysis (pull_request) Successful in 39s
CI / Tests (PHP 8.3) (pull_request) Successful in 40s
CI / Tests (PHP 8.1) (pull_request) Successful in 49s
CI / No Debug Code (pull_request) Successful in 35s
CI / Build Plugin Zip (pull_request) Skipped
main now requires signed commits, and Gitea refuses to merge a pull request
carrying an unsigned one, so the post-release bump PR could not be merged
without disabling the protection first.

The runner now signs that commit with a dedicated release-bot SSH key held as
an organisation Actions secret, trusted by the instance through
[repository.signing] TRUSTED_SSH_KEYS. The key Gitea signs merge commits with
lives on the server and no runner can reach it.

The step fails fast when the secret is missing, unparseable or passphrase
protected, and the commit is re-read before pushing so an unsigned one is
caught here rather than days later at merge time.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 20:25:58 -03:00
thatguygriff a4f694a966 Merge pull request 'Bump version to 1.5.7' (#198) from release/bump-1.5.7 into main
CI / Coding Standards (push) Successful in 21s
CI / Tests (PHP 8.1) (push) Successful in 30s
CI / Static Analysis (push) Successful in 36s
CI / Tests (PHP 8.2) (push) Successful in 40s
CI / Tests (PHP 8.5) (push) Successful in 25s
CI / Tests (PHP 8.3) (push) Successful in 36s
CI / No Debug Code (push) Successful in 37s
CI / Build Plugin Zip (push) Successful in 22s
Reviewed-on: #198
Reviewed-by: James Griffin-Allwood <[email protected]>
2026-09-05 19:45:41 -03:00
Release Bot b9f7c96ce6 Bump version to 1.5.7 and open changelog section 2026-09-05 15:04:47 +00:00
thatguygriff f58585be0d Merge pull request 'Fix five findings from a security assessment of the plugin' (#197) from security/assessment-hardening into main
CI / Coding Standards (push) Successful in 18s
CI / No Debug Code (push) Successful in 6s
CI / Tests (PHP 8.5) (push) Successful in 33s
CI / Static Analysis (push) Successful in 37s
CI / Tests (PHP 8.1) (push) Successful in 37s
CI / Tests (PHP 8.3) (push) Successful in 37s
CI / Tests (PHP 8.2) (push) Successful in 39s
CI / Build Plugin Zip (push) Successful in 12s
Release / Build and Publish Release (push) Successful in 25s
Release / Open next-version bump PR (push) Successful in 4s
Reviewed-on: #197
Reviewed-by: James Griffin-Allwood <[email protected]>
v1.5.6
2026-09-05 15:00:33 +00:00
KydoimosandClaude Opus 5 ae1a62883e Fix the CI failures in the uninstaller work
CI / Coding Standards (pull_request) Successful in 28s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.1) (pull_request) Successful in 38s
CI / Tests (PHP 8.3) (pull_request) Successful in 40s
CI / Tests (PHP 8.2) (pull_request) Successful in 49s
CI / Static Analysis (pull_request) Successful in 1m0s
CI / Tests (PHP 8.5) (pull_request) Successful in 57s
CI / Build Plugin Zip (pull_request) Skipped
Both were mine, and both were in code the earlier commit could not run.

The four test failures shared one cause: UninstallerTest stubbed get_option
with an arrow function, which captures by value, so every read answered from
a snapshot of the options taken at setUp — before the test set any and before
the run wrote any. Every assertion that depended on reading back what had
just been written therefore saw an empty store. The file's other stubs
already use by-reference closures; this one now does too.

The phpcs error is WordPress.DB.PreparedSQL.NotPrepared on the table drop.
The sniff cannot follow $sql across the null guard that PHPStan requires
(prepare() is nullable), and unlike the repositories — which call through a
typed $this->db property the sniff does not track at all — the uninstaller
calls the global $wpdb, so the sniff sees it. Silenced explicitly, with the
reason.

composer test (996 tests, 2871 assertions), composer lint and composer cs all
pass locally on PHP 8.4.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 11:55:53 -03:00
KydoimosandClaude Opus 5 1847159e31 Fix five findings from a security assessment of the plugin
The assessment looked for three things: whether students can reach each
other's bookings, whether payment settings can be dodged, and whether the
plugin opens a way into the rest of the install. The student-isolation and
payment paths held up. These are what did not.

- The front-end login form told WordPress not to work out whether the site
  was secure, so on HTTPS every student's session cookie was issued without
  the Secure flag. wp_signon() only derives it from is_ssl() when the second
  argument is left at its default; an explicit false reads like "no
  preference" and is not.

- The update check took whatever download URL the release API returned and
  handed it to core, which unpacks it over the installed plugin. The package
  must now be https on git.unsupervised.ca exactly, compared on the parsed
  host so a lookalike name cannot pass.

- Uninstalling dropped 2 of 14 tables and left the Stripe secret and webhook
  signing key in wp_options. Removal is now a choice made in advance on
  Access -> Plugin removal: records are kept unless the owner opts in (with a
  typed confirmation), while credentials and the borrowed core registration
  settings go every time.

- Open registration switches on the site-wide users_can_register and makes
  Student the default role, arming any other signup form on the site to mint
  students who could book and be billed immediately. The pending state is now
  decided once, on user_register, rather than by whichever form created the
  account.

- Cancel and withdraw answered "not yours" differently from "does not exist",
  which let a signed-in student enumerate the studio's bookings. Both now
  give the same 404.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-05 11:55:53 -03:00
thatguygriff 74df3f5ba8 Merge pull request 'Bump version to 1.5.6' (#196) from release/bump-1.5.6 into main
CI / Coding Standards (push) Successful in 25s
CI / No Debug Code (push) Successful in 7s
CI / Tests (PHP 8.5) (push) Successful in 36s
CI / Tests (PHP 8.1) (push) Successful in 44s
CI / Static Analysis (push) Successful in 46s
CI / Tests (PHP 8.2) (push) Successful in 45s
CI / Tests (PHP 8.3) (push) Successful in 49s
CI / Build Plugin Zip (push) Successful in 22s
Reviewed-on: #196
2026-09-05 11:54:29 -03:00
Release Bot f8f211929c Bump version to 1.5.6 and open changelog section 2026-08-25 02:20:56 +00:00
thatguygriff 61a40f0e8d Merge pull request 'Update stripe-php from 17.6.0 to 21.2.1' (#195) from feature/194-stripe-php-21 into main
CI / Coding Standards (push) Successful in 17s
CI / No Debug Code (push) Successful in 1s
CI / Tests (PHP 8.1) (push) Successful in 32s
CI / Tests (PHP 8.5) (push) Successful in 29s
CI / Tests (PHP 8.3) (push) Successful in 42s
CI / Static Analysis (push) Successful in 52s
CI / Tests (PHP 8.2) (push) Successful in 52s
CI / Build Plugin Zip (push) Successful in 23s
Release / Build and Publish Release (push) Successful in 20s
Release / Open next-version bump PR (push) Successful in 4s
Reviewed-on: #195
v1.5.5
2026-08-25 02:18:36 +00:00
thatguygriffandClaude Opus 5 88a8d0ae5c Date the Stripe changelog entry by version rather than by "current"
CI / Coding Standards (pull_request) Successful in 26s
CI / Tests (PHP 8.1) (pull_request) Successful in 28s
CI / No Debug Code (pull_request) Successful in 7s
CI / Tests (PHP 8.2) (pull_request) Successful in 36s
CI / Tests (PHP 8.5) (pull_request) Successful in 34s
CI / Static Analysis (pull_request) Successful in 37s
CI / Tests (PHP 8.3) (pull_request) Successful in 36s
CI / Build Plugin Zip (pull_request) Skipped
"the current Stripe library" is only true until Stripe ships the next major.
A changelog is read long after the release it describes, so name the
versions — 17 to 21, API version 2026-07-29.dahlia — and let those date the
entry.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2
2026-08-24 23:17:33 -03:00
thatguygriffandClaude Opus 5 e2da45a1b0 Update stripe-php from 17.6.0 to 21.2.1
CI / Coding Standards (pull_request) Successful in 27s
CI / No Debug Code (pull_request) Successful in 6s
CI / Tests (PHP 8.1) (pull_request) Successful in 35s
CI / Tests (PHP 8.2) (pull_request) Successful in 34s
CI / Tests (PHP 8.5) (pull_request) Successful in 24s
CI / Tests (PHP 8.3) (pull_request) Successful in 37s
CI / Static Analysis (pull_request) Successful in 45s
CI / Build Plugin Zip (pull_request) Skipped
Four majors behind on the plugin's only production dependency. No site is
using Stripe yet and the integration has not been verified end to end, so
the pinned API version can move now at close to zero cost — later it would
mean coordinating with live payment traffic.

The library surface this plugin uses is four symbols, all in StripeGateway:
StripeClient, paymentIntents->create, Webhook::constructEvent and Event.
Checked each against the installed v21 by reflection; all present with
compatible signatures. Most of the breakage flagged across 18 to 21 is in
the V2 Events API, which this does not use — webhooks go through the V1
Webhook::constructEvent path.

The pinned Stripe API version moves to 2026-07-29.dahlia.

Verified beyond the suite, which mocks the client: a real HMAC-signed
payload round-trips through Webhook::constructEvent and returns a
Stripe\Event with the expected type and data, and a forged signature still
raises SignatureVerificationException. The 21.0.0 ErrorObject retyping to
null|string produces no new PHPStan findings.

Part of #194

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2
2026-08-24 23:15:01 -03:00
thatguygriff dfa29745df Merge pull request 'Update the dev dependencies' (#193) from chore/update-dev-dependencies into main
CI / Coding Standards (push) Successful in 13s
CI / No Debug Code (push) Successful in 3s
CI / Tests (PHP 8.1) (push) Successful in 30s
CI / Tests (PHP 8.5) (push) Successful in 30s
CI / Tests (PHP 8.2) (push) Successful in 46s
CI / Tests (PHP 8.3) (push) Successful in 45s
CI / Static Analysis (push) Successful in 54s
CI / Build Plugin Zip (push) Successful in 9s
Reviewed-on: #193
2026-08-25 02:10:14 +00:00
thatguygriffandClaude Opus 5 54a8b906f7 Update the dev dependencies
CI / Coding Standards (pull_request) Successful in 20s
CI / No Debug Code (pull_request) Successful in 5s
CI / Static Analysis (pull_request) Successful in 31s
CI / Tests (PHP 8.2) (pull_request) Successful in 31s
CI / Tests (PHP 8.1) (pull_request) Successful in 32s
CI / Tests (PHP 8.3) (pull_request) Successful in 32s
CI / Tests (PHP 8.5) (pull_request) Successful in 35s
CI / Build Plugin Zip (pull_request) Skipped
Routine catch-up on the test and analysis tooling. Every package here is
already allowed by the existing constraints, so composer.json does not move
and no production dependency is touched.

  mockery/mockery              1.6.12  -> 1.6.15
  phpstan/phpstan               2.2.2  -> 2.2.9
  phpunit/phpunit             10.5.63  -> 10.5.64
  hamcrest/hamcrest-php        v2.1.1  -> v3.0.0   (transitive, via mockery)
  myclabs/deep-copy            1.13.4  -> 1.14.0
  nikic/php-parser             v5.7.0  -> v5.8.0
  sebastian/recursion-context   5.0.1  -> 5.0.2

Seven patch releases of PHPStan is the one worth watching, since a static
analyser routinely gains inferences between them. It reports no new errors
here, and PHPCS and the suite are unchanged.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2
2026-08-24 23:08:54 -03:00
thatguygriff b3ed3a67d5 Merge pull request 'Pin the Composer platform to PHP 8.1 and clear the PHPCS security advisories' (#192) from fix/187-composer-platform-pin into main
CI / Coding Standards (push) Successful in 17s
CI / No Debug Code (push) Successful in 2s
CI / Tests (PHP 8.2) (push) Successful in 32s
CI / Tests (PHP 8.1) (push) Successful in 48s
CI / Static Analysis (push) Successful in 38s
CI / Tests (PHP 8.3) (push) Successful in 47s
CI / Tests (PHP 8.5) (push) Successful in 47s
CI / Build Plugin Zip (push) Successful in 21s
Reviewed-on: #192
2026-08-25 02:08:07 +00:00
thatguygriffandClaude Opus 5 908b7fcd1f Update the coding-standards tooling off three security advisories
CI / Coding Standards (pull_request) Successful in 16s
CI / No Debug Code (pull_request) Successful in 4s
CI / Tests (PHP 8.3) (pull_request) Successful in 21s
CI / Tests (PHP 8.5) (pull_request) Successful in 22s
CI / Tests (PHP 8.2) (pull_request) Successful in 48s
CI / Tests (PHP 8.1) (pull_request) Successful in 49s
CI / Static Analysis (pull_request) Successful in 57s
CI / Build Plugin Zip (pull_request) Skipped
composer audit reported three advisories against the PHPCS stack, two rated
high:

  squizlabs/php_codesniffer  3.13.5 -> 3.13.6  CVE-2026-67434, OS command injection
  wp-coding-standards/wpcs   3.3.0  -> 3.4.1   CVE-2026-45293, arbitrary code execution
  phpcsstandards/phpcsutils  1.2.2  -> 1.2.3   CVE-2026-65954, arbitrary code execution

All three are dev-only and none ship in the plugin — bin/build-zip.sh installs
--no-dev — but they execute against repository content on every CI run.

The existing ^3.7 and ^3.0 constraints already allowed the fixed releases, so
composer.json is unchanged. phpcsextra and the codesniffer installer come
along as transitive dependencies. Five packages move, none are added or
removed, and the updated standards report no new violations.

composer audit is now clean.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2
2026-08-24 22:50:34 -03:00
thatguygriffandClaude Opus 5 b17adf02ff Pin the Composer platform to PHP 8.1
CI / Tests (PHP 8.2) (pull_request) Successful in 26s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.3) (pull_request) Successful in 29s
CI / Tests (PHP 8.5) (pull_request) Successful in 30s
CI / Coding Standards (pull_request) Successful in 36s
CI / Tests (PHP 8.1) (pull_request) Successful in 46s
CI / Static Analysis (pull_request) Successful in 49s
CI / Build Plugin Zip (pull_request) Skipped
composer.json declares "php": ">=8.1", but resolution ran against whatever
PHP the machine doing the update happened to have. Running composer update
on 8.5 could therefore produce a lock containing a package that requires 8.2
or newer, which installs fine locally and fails on the 8.1 leg of the test
matrix — a lock that is only discovered to be wrong in CI.

config.platform.php makes resolution always target the declared minimum, so
a lock that resolves at all is a lock that installs everywhere the plugin
claims to run.

No package versions change: nothing currently locked requires a PHP newer
than 8.1, so this only records platform-overrides and the new content hash.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2
2026-08-24 22:46:11 -03:00
thatguygriff a23490ec80 Merge pull request 'CI: run jobs in shared ci-php images, commit composer.lock' (#191) from feature/187-run-jobs-in-ci-images into main
CI / Coding Standards (push) Successful in 16s
CI / No Debug Code (push) Successful in 5s
CI / Tests (PHP 8.3) (push) Successful in 25s
CI / Tests (PHP 8.5) (push) Successful in 31s
CI / Static Analysis (push) Successful in 37s
CI / Tests (PHP 8.2) (push) Successful in 35s
CI / Tests (PHP 8.1) (push) Successful in 39s
CI / Build Plugin Zip (push) Successful in 9s
Reviewed-on: #191
2026-08-25 01:41:19 +00:00
thatguygriffandClaude Opus 5 1552bf4b5f Move the CI image definitions to the shared ci-php repository
CI / Coding Standards (pull_request) Successful in 14s
CI / Tests (PHP 8.1) (pull_request) Successful in 30s
CI / Tests (PHP 8.2) (pull_request) Successful in 30s
CI / Tests (PHP 8.3) (pull_request) Successful in 29s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.5) (pull_request) Successful in 21s
CI / Static Analysis (pull_request) Successful in 37s
CI / Build Plugin Zip (pull_request) Skipped
The image definition and its publishing workflow were only here because this
was the first project to need them. They are project-agnostic, so they now
live in Unsupervised/ci-php and any PHP project can consume the same tags.
The registry path is unchanged — Gitea container images are named
owner/image, not after the repository that pushes them — so nothing here
needs repointing.

Split the combined quality job into separate phpcs and phpstan jobs. They
were folded together to halve the number of toolchain installs per run; with
the toolchain in the image that saves nothing, and separating them means a
coding-standards failure no longer hides the static analysis result.

Rewrite the workflow comments to describe what the jobs do rather than the
setup step they replaced, and cut docs/ci.md down to what is specific to this
project — the image contents and publishing are documented in ci-php.

Closes #187

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2
2026-08-24 22:39:08 -03:00
thatguygriffandClaude Opus 5 f8762e1095 Correct the registry auth docs: the Actions token does not work
CI Images / Build CI image (PHP 8.2) (pull_request) Successful in 3s
CI Images / Build CI image (PHP 8.5) (pull_request) Successful in 8s
CI / Tests (PHP 8.3) (pull_request) Successful in 30s
CI Images / Build CI image (PHP 8.3) (pull_request) Successful in 4s
CI / Tests (PHP 8.2) (pull_request) Successful in 23s
CI / Tests (PHP 8.1) (pull_request) Successful in 28s
CI / No Debug Code (pull_request) Successful in 4s
CI / Coding Standards & Static Analysis (pull_request) Successful in 43s
CI / Tests (PHP 8.5) (pull_request) Successful in 23s
CI / Build Plugin Zip (pull_request) Skipped
CI Images / Build CI image (PHP 8.1) (pull_request) Successful in 1m3s
docs/ci.md and the workflow comment both described secrets.GITHUB_TOKEN as
the working credential with REGISTRY_TOKEN as a fallback. That is backwards:
the task token is rejected by Gitea's container registry (go-gitea/gitea#23642)
and the first publish attempt failed on exactly that. REGISTRY_TOKEN is
required.

Part of #187

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2
2026-08-24 22:35:10 -03:00
thatguygriffandClaude Opus 5 c9d18fec74 Commit composer.lock so CI and releases install a fixed dependency set
CI / Tests (PHP 8.2) (pull_request) Successful in 25s
CI / Tests (PHP 8.1) (pull_request) Successful in 26s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.3) (pull_request) Successful in 32s
CI / Coding Standards & Static Analysis (pull_request) Successful in 42s
CI / Tests (PHP 8.5) (pull_request) Successful in 32s
CI / Build Plugin Zip (pull_request) Skipped
composer.lock was gitignored, so `composer install` resolved the graph afresh
on every job. CI could quietly start testing different dependency versions
than it did the day before, and two builds of the same tag could ship
different vendor trees — the run that produces the zip is the same run that
picks the versions.

Track the lock, and make the two places that consume it use it:

- the Composer cache keys hash composer.lock rather than composer.json, since
  the lock is now what actually fingerprints the dependency set;
- bin/build-zip.sh stages the lock alongside composer.json, so the --no-dev
  production install resolves to the locked versions. It already deleted both
  from the staging directory before zipping, so the shipped plugin is
  unchanged.

The current lock installs cleanly on 8.1: nothing in it requires a PHP newer
than the >=8.1 composer.json declares.

Closes #187

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2
2026-08-24 22:33:04 -03:00
thatguygriffandClaude Opus 5 ab609898d6 Run CI and release jobs inside the prebuilt CI images
CI / Coding Standards & Static Analysis (pull_request) Successful in 37s
CI / Tests (PHP 8.1) (pull_request) Successful in 21s
CI / Tests (PHP 8.2) (pull_request) Successful in 20s
CI / Tests (PHP 8.3) (pull_request) Successful in 19s
CI / Tests (PHP 8.5) (pull_request) Successful in 19s
CI / No Debug Code (pull_request) Successful in 2s
CI / Build Plugin Zip (pull_request) Skipped
Replaces setup-php with `container:` in every job that needs PHP. The images
published by ci-images.yml already carry PHP, Composer, the intl and zip
extensions and the CLI tools the workflow scripts shell out to, so nothing
installs PHP at job time any more.

That removes the apt path #178 was about: a ~145s floor on 8.3 against ~35s
on 8.1/8.2, with a tail that twice ran past the step timeout and failed the
run. All three copies of the `Keep downloaded .debs` / `Cache apt packages`
workaround go with it.

no-debug and bump-version stay on the runner image — neither needs PHP, and
no-debug wants the runner's GNU `grep --include`.

The Composer cache moves to /composer/cache, which is COMPOSER_HOME in the
image, and release.yml gains the cache step it never had.

Also corrects the image size in docs/ci.md to the 67MB measured from the
published manifest; the ~120MB in the original was an estimate.

Closes #187

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2
2026-08-24 22:25:02 -03:00
thatguygriff 4bc8e80837 Merge pull request 'CI: install GNU tar in the CI image so actions/cache works' (#190) from fix/187-ci-image-gnu-tar into main
CI Images / Build CI image (PHP 8.3) (push) Successful in 1m14s
CI Images / Build CI image (PHP 8.2) (push) Successful in 1m30s
CI Images / Build CI image (PHP 8.1) (push) Successful in 1m31s
CI Images / Build CI image (PHP 8.5) (push) Successful in 1m54s
CI / Tests (PHP 8.2) (push) Successful in 52s
CI / No Debug Code (push) Successful in 2s
CI / Tests (PHP 8.5) (push) Successful in 3m0s
CI / Tests (PHP 8.1) (push) Successful in 6m0s
CI / Tests (PHP 8.3) (push) Successful in 6m1s
CI / Coding Standards & Static Analysis (push) Failing after 17m19s
CI / Build Plugin Zip (push) Skipped
Reviewed-on: #190
2026-08-25 01:23:12 +00:00
thatguygriffandClaude Opus 5 28f586d207 Install GNU tar in the CI image so actions/cache works
CI Images / Build CI image (PHP 8.1) (pull_request) Successful in 48s
CI / Tests (PHP 8.1) (pull_request) Successful in 55s
CI Images / Build CI image (PHP 8.2) (pull_request) Successful in 1m46s
CI Images / Build CI image (PHP 8.3) (pull_request) Successful in 1m48s
CI Images / Build CI image (PHP 8.5) (pull_request) Successful in 2m26s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.2) (pull_request) Successful in 53s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m50s
CI / Tests (PHP 8.5) (pull_request) Successful in 2m58s
CI / Coding Standards & Static Analysis (pull_request) Failing after 17m18s
CI / Build Plugin Zip (pull_request) Skipped
actions/cache shells out to `tar --posix -P`. Alpine's busybox tar rejects
both flags, so the cache step would fail in every job that runs inside these
images — which is all of them once ci.yml switches over.

coreutils does not cover this: tar is its own Alpine package. Add it, add
zstd (which actions/cache prefers over gzip when present), and assert GNU
tar in the image's smoke test so a future base-image change cannot quietly
drop it again.

Part of #187

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2
2026-08-24 22:15:40 -03:00
thatguygriff e097b7a0bf Merge pull request 'CI: publish prebuilt CI images to the Gitea container registry' (#188) from feature/187-ci-container-images into main
CI Images / Build CI image (PHP 8.1) (push) Failing after 5s
CI Images / Build CI image (PHP 8.2) (push) Failing after 7s
CI Images / Build CI image (PHP 8.3) (push) Failing after 6s
CI Images / Build CI image (PHP 8.5) (push) Failing after 17s
CI / No Debug Code (push) Successful in 9s
CI / Tests (PHP 8.2) (push) Successful in 52s
CI / Tests (PHP 8.3) (push) Successful in 2m47s
CI / Coding Standards & Static Analysis (push) Successful in 3m41s
CI / Tests (PHP 8.1) (push) Successful in 5m59s
CI / Tests (PHP 8.5) (push) Successful in 7m5s
CI / Build Plugin Zip (push) Successful in 6m0s
Reviewed-on: #188
2026-08-25 01:05:33 +00:00
thatguygriffandClaude Opus 5 572aaf5b49 Publish prebuilt CI images to the Gitea container registry
CI Images / Build CI image (PHP 8.2) (pull_request) Successful in 1m14s
CI Images / Build CI image (PHP 8.1) (pull_request) Successful in 1m26s
CI Images / Build CI image (PHP 8.3) (pull_request) Successful in 2m3s
CI Images / Build CI image (PHP 8.5) (pull_request) Successful in 2m9s
CI / Tests (PHP 8.2) (pull_request) Successful in 1m7s
CI / No Debug Code (pull_request) Successful in 2s
CI / Tests (PHP 8.3) (pull_request) Successful in 3m8s
CI / Tests (PHP 8.1) (pull_request) Successful in 5m55s
CI / Tests (PHP 8.5) (pull_request) Successful in 6m21s
CI / Coding Standards & Static Analysis (pull_request) Successful in 18m26s
CI / Build Plugin Zip (pull_request) Skipped
setup-php installs PHP 8.3+ from apt on these arm64 runners: a ~145s floor
against ~35s for 8.1/8.2, with a tail that twice ran past the step timeout
and failed the run (#178). Caching the .debs softened it without removing
the apt step, and 8.5 has the same problem.

Add a per-version CI image built on php:<version>-cli-alpine and a workflow
that publishes it to git.unsupervised.ca/unsupervised/ci-php:<version>. The
org is public, so the packages pull anonymously.

The image carries bash and nodejs because act_runner runs JavaScript actions
inside the job container, GNU coreutils/grep/sed because the workflow scripts
use `tac` and `grep --include`, and curl/jq/git/zip for release.yml and
bin/build-zip.sh. Composer 2 and the intl and zip extensions round it out.

Nothing consumes the images yet — ci.yml and release.yml switch over in a
follow-up, because a job cannot run in an image that has not been published.

Part of #187

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01D9acV1mHktGAb1uyvNmrR2
2026-08-24 21:55:28 -03:00
thatguygriff 116394f2ff Merge pull request 'Bump version to 1.5.5' (#189) from release/bump-1.5.5 into main
CI / No Debug Code (push) Successful in 3s
CI / Tests (PHP 8.1) (push) Successful in 53s
CI / Tests (PHP 8.5) (push) Successful in 3m28s
CI / Tests (PHP 8.3) (push) Successful in 5m46s
CI / Tests (PHP 8.2) (push) Successful in 6m14s
CI / Coding Standards & Static Analysis (push) Failing after 12m16s
CI / Build Plugin Zip (push) Skipped
Reviewed-on: #189
2026-08-25 00:50:11 +00:00
Release Bot dda8386c1f Bump version to 1.5.5 and open changelog section 2026-08-24 23:50:02 +00:00
thatguygriff 7278309bf5 Merge pull request 'Let the studio register the students who cannot register themselves' (#186) from fix/185-book-for-child-and-vet-group-enrolment into main
CI / Coding Standards & Static Analysis (push) Successful in 13m23s
CI / Tests (PHP 8.1) (push) Successful in 55s
CI / Tests (PHP 8.2) (push) Successful in 1m7s
CI / Tests (PHP 8.3) (push) Successful in 6m59s
CI / Tests (PHP 8.5) (push) Successful in 12m55s
CI / No Debug Code (push) Successful in 3s
CI / Build Plugin Zip (push) Successful in 5m53s
Release / Build and Publish Release (push) Successful in 8m5s
Release / Open next-version bump PR (push) Successful in 5s
Reviewed-on: #186
v1.5.4
2026-08-24 22:03:11 +00:00
thatguygriffandClaude Opus 5 5ce42f0003 Let the studio register the students who cannot register themselves
CI / No Debug Code (pull_request) Successful in 4s
CI / Tests (PHP 8.2) (pull_request) Successful in 50s
CI / Tests (PHP 8.1) (pull_request) Successful in 1m3s
CI / Tests (PHP 8.5) (pull_request) Successful in 2m48s
CI / Tests (PHP 8.3) (pull_request) Successful in 3m24s
CI / Coding Standards & Static Analysis (pull_request) Successful in 8m21s
CI / Build Plugin Zip (pull_request) Skipped
The Book a lesson for a student panel built its picker from the us_student
role but vetted the submission with the book_lesson capability. ChildLoginGate
and RegistrationLoginGate withhold that capability from accounts that keep the
role, so the panel offered every guardian-managed child and every unapproved
signup and then refused them — with a message claiming no student had been
chosen, and a form cleared of all five fields.

Withholding book_lesson stops those accounts registering in their own name. It
was never meant to stop the studio acting for them, which is what the panel is
for, and for a child is the only route to a lesson besides their guardian.

Guard the student role instead, via a new RoleManager::isStudent() shared with
every picker and guard on the staff side so the two cannot drift apart again.
Group enrolment gets the same predicate: addDirect() and grantAccess() vetted
their posted ids not at all, and would enrol an instructor, an administrator,
or an account deleted since the page was drawn — raising a real payment against
them for a priced class.

Keep a refused booking's fields as submitted, reading the form through one
LessonController::submittedBooking() so what gets booked and what is shown
again cannot disagree about a field name. A booking that succeeds still leaves
an empty form, so the next one does not inherit it.

Closes #185

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XunBYk2sFEc1oL14sUiuBU
2026-08-24 18:42:59 -03:00
thatguygriff 76530878b5 Merge pull request 'Bump version to 1.5.4' (#184) from release/bump-1.5.4 into main
CI / Tests (PHP 8.1) (push) Successful in 58s
CI / No Debug Code (push) Successful in 2s
CI / Tests (PHP 8.5) (push) Successful in 4m20s
CI / Coding Standards & Static Analysis (push) Successful in 5m21s
CI / Tests (PHP 8.2) (push) Successful in 6m4s
CI / Tests (PHP 8.3) (push) Successful in 12m56s
CI / Build Plugin Zip (push) Successful in 2m39s
Reviewed-on: #184
2026-08-24 17:59:40 +00:00
Release Bot 6031a75012 Bump version to 1.5.4 and open changelog section 2026-08-24 17:56:38 +00:00
thatguygriff 41843e5253 Merge pull request 'Let the studio book lessons and record intake collected elsewhere' (#183) from feature/182-admin-booking-and-intake-recording into main
Release / Build and Publish Release (push) Successful in 4m43s
Release / Open next-version bump PR (push) Successful in 3s
CI / Tests (PHP 8.1) (push) Successful in 51s
CI / Tests (PHP 8.2) (push) Successful in 56s
CI / Tests (PHP 8.3) (push) Successful in 4m41s
CI / Tests (PHP 8.5) (push) Successful in 3m6s
CI / No Debug Code (push) Successful in 4s
CI / Coding Standards & Static Analysis (push) Successful in 8m23s
CI / Build Plugin Zip (push) Successful in 2m39s
Reviewed-on: #183
v1.5.3
2026-08-24 17:50:46 +00:00
thatguygriffandClaude Opus 5 8c21a3fa9d Let the studio book lessons and record intake collected elsewhere
CI / Tests (PHP 8.1) (pull_request) Successful in 6m39s
CI / Tests (PHP 8.2) (pull_request) Successful in 57s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m59s
CI / Tests (PHP 8.5) (pull_request) Successful in 3m31s
CI / No Debug Code (pull_request) Successful in 3s
CI / Coding Standards & Static Analysis (pull_request) Successful in 3m28s
CI / Build Plugin Zip (pull_request) Skipped
Two related gaps, closed together because the second is created by the first.

A private lesson could only be booked by the student or their guardian, so a
booking taken over the phone had no way in — where group classes have had "Add
students directly" all along. "Book a lesson for a student" is now a panel on
Scheduler and My Lessons: student, open time, lesson type, with weekly term
reservations and a no-charge option for make-up lessons. The booking core is
extracted to Booking\LessonBooker and shared with POST /bookings, so the two
paths cannot drift on offering rules, slot claiming, or billing.

That leaves a registration with no intake answers and no policy acceptances,
because nobody was at a keyboard to give them — already true of every directly
added group-class student. Ticking the boxes on a student's behalf would be an
audit trail that says something untrue, so instead the answers are collected
another way and recorded afterwards, from a lesson's or an enrolment's detail
page. Every recording must say how it was collected, which is stamped on each
row along with who typed it and shown in a new "How it was given" column: a
policy ticked online and one transcribed from paper must never look alike.

Only staff-made registrations qualify (us_lessons.booked_by,
us_group_enrollments.enrolled_by) — one the student made already holds their
own answers. Only what is still missing can be recorded, re-checked at write
time, so a stale or double-posted form cannot duplicate or overwrite. No IP is
stored for a transcription, and accepted_by stays the student while recorded_by
names the staff member.

Intake is now generic over Registration\IntakeSubject, which Lesson and
Enrollment both implement; LessonDetail became Registration\IntakeAudit and is
shared by both detail views rather than duplicated.

Closes #182

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QfHt6CyJHz6KkA4RuaS7WK
2026-08-24 14:06:16 -03:00
thatguygriff 8a34ec41e9 Merge pull request 'Cache the packages php-builder installs, and restore PHP 8.5' (#181) from ci/cache-php-builder-deps into main
CI / No Debug Code (push) Successful in 3s
CI / Tests (PHP 8.2) (push) Successful in 2m27s
CI / Tests (PHP 8.1) (push) Successful in 2m33s
CI / Tests (PHP 8.3) (push) Successful in 2m55s
CI / Coding Standards & Static Analysis (push) Successful in 3m26s
CI / Tests (PHP 8.5) (push) Successful in 7m59s
CI / Build Plugin Zip (push) Successful in 6m59s
Reviewed-on: #181
2026-08-20 19:18:46 +00:00
thatguygriffandClaude Opus 5 37c8d2b39e Put PHP 8.5 back in the matrix
CI / No Debug Code (pull_request) Successful in 4s
CI / Tests (PHP 8.2) (pull_request) Successful in 55s
CI / Tests (PHP 8.1) (pull_request) Successful in 1m15s
CI / Tests (PHP 8.5) (pull_request) Successful in 6m41s
CI / Tests (PHP 8.3) (pull_request) Failing after 12m21s
CI / Coding Standards & Static Analysis (pull_request) Successful in 13m48s
CI / Build Plugin Zip (pull_request) Skipped
I misread the instruction to hold 8.5 as "take it out until the cache
lands" and removed it in f6481d4, so #179 merged without it. It was meant
to stay where it was. Restoring it.

8.5 takes the same php-builder path as 8.3, so the apt cache in this
branch is exactly what it needs, and the per-version key means it caches
its own ~70 -dev packages rather than sharing with the ondrej-path jobs.

composer test passes on 8.5.9 locally: 915 tests, 2592 assertions.

Refs #178.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Uw545F1vveNJKjzLxdi2ks
2026-08-20 16:04:52 -03:00
thatguygriffandClaude Opus 5 a90e06ae70 Key the apt cache per PHP version and drop the instrumentation
CI / No Debug Code (pull_request) Successful in 26s
CI / Tests (PHP 8.1) (pull_request) Successful in 2m35s
CI / Tests (PHP 8.2) (pull_request) Successful in 2m35s
CI / Coding Standards & Static Analysis (pull_request) Successful in 4m1s
CI / Tests (PHP 8.3) (pull_request) Failing after 7m17s
CI / Build Plugin Zip (pull_request) Skipped
Run 536 proved the cache works -- ACTIONS_CACHE_URL is now populated, no
GHES warning, "Cache saved with key: apt-php-builder-deps-ARM64-v1" -- and
in doing so showed the key was wrong. The jobs that saved it were 8.1 and
8.2.

They take the ondrej PPA path, a handful of runtime packages, while 8.3
takes php-builder and its ~70 -dev packages. One shared key therefore lets
whichever job finishes first decide what every other job restores, and 8.1
is always first, at ~30s against 8.3's several minutes. 8.3 would have
restored a few runtime .debs it has no use for and then downloaded all 70
anyway. My "the dep list is the same for every PHP version" comment was
true only among the builder versions.

Keyed per version now, so each path caches what it actually installs. That
also picks up a small win on 8.1 and 8.2 rather than only avoiding harm.

Both temporary steps are gone. Report restored .debs was there to show the
cache URL arriving and the restore landing; both are established, so it
goes. Keep downloaded .debs stays -- it is not instrumentation, it disables
Ubuntu's docker-clean, without which there are no .debs left to cache.

Refs #178.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Uw545F1vveNJKjzLxdi2ks
2026-08-20 15:57:27 -03:00
thatguygriffandClaude Opus 5 d5f6ebf0b5 Move actions/cache to v4 and probe the cache URL
thatguygriff/infra#1 turned the runner cache server on, so actions/cache
has an endpoint for the first time. v4 rather than v3 because v4.2+ can
speak the cache service v2 API, which is what the runner serves.

The instrumentation step now also prints ACTIONS_CACHE_URL, so a single
run shows the endpoint arriving and the cache being read in one log
rather than needing a separate probe.

Refs #178.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Uw545F1vveNJKjzLxdi2ks
2026-08-20 15:56:37 -03:00
thatguygriffandClaude Opus 5 4b4b2453ae Cache the .debs php-builder installs, to measure whether it helps
Experiment for #178. On self-hosted runners setup-php installs PHP 8.3+
through php-builder, whose install.sh apt-installs ~70 -dev packages
before unpacking the build. The build tarball itself is only 19MB, so
that apt work is the whole cost, not the download.

Ubuntu's image drops the .debs after install, so every job fetches them
from the archive again. This keeps them and restores them through the
cache server, which lives in the cluster, so a WAN download becomes a
local one. The dependency list does not vary by PHP version, so a single
key serves 8.3 and 8.5 and the quality and build jobs alike.

Only the .debs are cached. /var/lib/apt/lists is deliberately left alone,
since a stale index is how apt starts 404ing mid-install, and reducing
flakiness is the entire point.

The Report restored .debs step is temporary instrumentation to show
whether the cache is actually being read. Baseline to beat, from run 526:
8.1 30s, 8.2 53s, 8.3 454s, quality 151s, 8.5 733s and a hard failure.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Uw545F1vveNJKjzLxdi2ks
2026-08-20 15:56:37 -03:00
thatguygriff 7f10769330 Merge pull request 'Fold PHPCS and PHPStan into one job' (#179) from ci/consolidate-quality-job-and-php-85 into main
CI / Tests (PHP 8.2) (push) Canceled after 1s
CI / Tests (PHP 8.1) (push) Successful in 34s
CI / No Debug Code (push) Successful in 27s
CI / Build Plugin Zip (push) Skipped
CI / Coding Standards & Static Analysis (push) Successful in 10s
CI / Tests (PHP 8.3) (push) Canceled after 15s
Reviewed-on: #179
2026-08-20 18:55:16 +00:00
thatguygriffandClaude Opus 5 f6481d4a3f Hold PHP 8.5 until the runner serves a cache
CI / No Debug Code (pull_request) Successful in 3s
CI / Coding Standards & Static Analysis (pull_request) Successful in 3m37s
CI / Tests (PHP 8.3) (pull_request) Successful in 13m2s
CI / Build Plugin Zip (pull_request) Skipped
CI / Tests (PHP 8.1) (pull_request) Successful in 1m21s
CI / Tests (PHP 8.2) (pull_request) Successful in 1m22s
8.5 lands on setup-php's php-builder path, same as 8.3, so it pays for
~70 apt -dev packages on every run. It timed out in run 526 and passed in
527 on identical code, which is a coin toss, and merging it would mean
intermittent red for a version nothing ships on yet.

The code is fine on 8.5 — verified locally on 8.5.9: 915 tests, PHPStan
and PHPCS clean, check-platform-reqs satisfied. This is purely about the
runners, so 8.5 comes back once #178 is fixed and the matrix is cheap
again. This PR is now just the PHPCS/PHPStan consolidation.

Refs #178.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Uw545F1vveNJKjzLxdi2ks
2026-08-20 15:33:03 -03:00
thatguygriffandClaude Opus 5 43b903c1c8 Revert the v4 cache retry: the gate stays shut, so it is the runner
CI / Tests (PHP 8.2) (pull_request) Successful in 53s
CI / Tests (PHP 8.1) (pull_request) Successful in 1m3s
CI / No Debug Code (pull_request) Successful in 2s
CI / Coding Standards & Static Analysis (pull_request) Successful in 3m27s
CI / Tests (PHP 8.3) (pull_request) Successful in 6m47s
CI / Tests (PHP 8.5) (pull_request) Failing after 12m17s
CI / Build Plugin Zip (pull_request) Skipped
Tested and the hypothesis is dead. actions/cache@v4 resolved properly
(SHA 0057852) and printed the same GHES warning as v3, so the action
version was not what was closing the gate.

That points at the runner rather than the action. Gitea's docs say the
runner patches the GHES check out of the action's bundle only when it
recognises it, and that a bundle it does not recognise "is left alone".
No patching for either v3 or v4, and no ACTIONS_CACHE_URL to patch it
towards, is what you get when cache is simply off in the runner config.

So the fix is cache.enabled in act_runner's config.yaml, with host set to
an address job containers can reach. Nothing in this repository unblocks
it, and inert steps are what let the Composer cache rot unnoticed, so the
experiment comes out again. Both halves — the apt cache and the move to
v4 — should land together once the runner serves a cache.

Refs #178.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Uw545F1vveNJKjzLxdi2ks
2026-08-20 15:07:18 -03:00