История коммитов

.
docs(agents): add the caching guide
.
feat(cache): add commands to clear and prune the application cache
.
refactor(cache): replace illuminate/cache with a tag-aware cache on symfony/cache
.
chore(docker): give composer a writable cache directory
Composer runs as www-data, whose home directory is owned by root, so every run
in the container warned that it could not create its cache and proceeded
without one.

COMPOSER_HOME now points at an explicit path that both image stages create and
chown after the user id is adjusted, and compose mounts a named volume over it
so the cache survives container recreation.
.
chore: raise the minimum php version to 8.4
The docker image already moved to 8.4; this brings the rest of the project in
line so the declared requirement, the CI matrix and the runtime checks agree.

- composer.json requires ^8.4 (lock file refreshed), the test workflow builds on
8.4 and the readme states it
- SystemChecker::MIN_PHP_VERSION was still 7.3 and the second installer step
duplicated the bound as literals; the checker is now the single source of
truth and the step reads from it
- phpstan baseline regenerated: the platform version appears in three ignored
patterns, the error count is unchanged
.
chore(docker): rename the compose project and dev domain to johncms
The stack ran under the johncms9 project name, which pinned the container names
and the local domain to the 9.x line.

- .env.example now ships johncms / johncms.loc
- the agent guides target the johncms.php-fpm container
- verify.sh reads COMPOSE_PROJECT_NAME from .env instead of hard-coding the
container name, and matches it exactly so a similarly named project on the
same host cannot be picked up by mistake
.
i18n(admin): translate the mail settings screen into russian
The 28 strings of the new screen, appended to ru.po without touching what was there, and the dictionary regenerated from it. The other languages come from Crowdin.
.
chore(i18n): regenerate the message templates
The templates had drifted from the sources: apart from the strings of the new mail settings screen, which land in the admin domain, every change is a line number.
.
fix(security): keep a policy from widening the link schemes of another
The library keeps its scheme validators in a registry shared by the whole process and, with the override it enables by default, hands out one that is already there without checking it against the policy being applied. One policy allowing http therefore let every policy built after it through as well, however narrow its own list of schemes - so a policy declaring https only accepted http, mailto and ftp as soon as anything else had sanitized a link first.

Not an XSS hole: javascript: and data: are refused by other means. What leaked are the ordinary schemes a policy deliberately left out.

This is what the flaky CustomHtmlPolicyTest was reporting: the suite runs defects first, so a failure moved the test to the front of the queue, where nothing had built a purifier yet and it passed again. With --order-by=default it failed every time. The regression test now builds the permissive policy first, the way the defect needs.
.
docs: bump the documentation submodule