One set of rules, checked by machines, for every Pollora repository: code quality, tests, security, performance and the public contract. The same gates run on a developer's machine, in a coding agent's hooks and in CI, so a change that breaks something is stopped before it is merged.
The harness follows five principles:
- A rule exists only if a machine checks it. Each rule has an identifier (
ARCH-02,SEC-03…) quoted in every failure. - A ratchet, not a big bang. Every metric starts from where the repository is today and may only improve.
- One harness, configured once. Repositories declare what they are (a profile); the harness decides how they are checked.
- The public contract is sacred. Attributes, hooks fired, configuration keys and commands only break in a major version.
- Developer simplicity stays the compass. The harness constrains the framework's code, never how a Pollora project is written.
composer require --dev pollora/harness
vendor/bin/pollora-qa init --profile=core
composer qainit never overwrites a file. It writes .harness.json, adds the harness preset to phpstan.neon, and creates what is missing: tests/Arch.php, rector.php, .github/workflows/harness.yml, .claude/settings.json, AGENTS.md, and the qa and qa:fast Composer scripts. Review the diff, commit, and the repository is in observe mode: every gate runs and reports, none blocks. Switch .harness.json to "mode": "enforce" once the reports are clean.
| Profile | For | Notable rules |
|---|---|---|
core |
Standalone packages (hook, discovery, media…) |
Laravel-free (ARCH-04), hexagon, downstream run of the framework |
framework |
pollora/framework |
Hexagon, Larastan, no third-party plugin in the core (ARCH-05) |
integration |
Packages built on the framework (metabox-bridge, debugbar, nectar) |
Larastan |
wp-plugin |
WordPress plugins distributed on their own | PHPStan max target |
template |
Themes, plugin and module templates, the skeleton | |
project |
Client projects built on Pollora | The security rules apply to the project's code |
| Command | Does |
|---|---|
pollora-qa check |
Every gate (G1 and G2): style, PHPStan, Rector, tests and architecture, dependency policy and analysis, Semgrep, composer audit, ratchet |
pollora-qa check --fast |
The fast gates (G0) on the files changed in the working tree |
pollora-qa ratchet [--update] |
Compares the metrics with .harness.json; --update records improvements, never regressions |
pollora-qa deps |
Checks the declared dependencies against the profile |
pollora-qa surface [--update] |
Compares the public surface with api-surface.json; --update records it |
pollora-qa rules [ID] |
Lists the rules, or explains one |
pollora-qa agents |
Regenerates the harness block of AGENTS.md |
pollora-qa hook <event> |
Agent hooks: pre-edit, post-edit, stop |
check writes .harness/report.json and, in GitHub Actions, a table in the job summary.
- Presets in
presets/: Pint, PHPStan (base.neon, pluslaravel.neonand the opt-instrict.neon), Semgrep rules, and the Rector preset classPollora\Harness\Rector\Preset. - ARCH-02 as a PHPStan rule: code in a
Domainnamespace calls no global WordPress function (pollora.noWordPressCallInDomain). - Architecture tests registered by
tests/Arch.phpfrom the layers found under the PSR-4 roots (Domain,Application,Infrastructure/Adapter,UI). - A reusable workflow,
.github/workflows/php-package.yml: quality gates, a test matrix (PHP × lowest/stable dependencies), a gitleaks scan, and the downstream job that runs the framework's tests against a changed core package. - Agent hooks for Claude Code: style fixed after each edit, PHPStan on the edited file, protected threshold files (QA-02), the fast gates before the agent hands back.
Projects built on Pollora rely on more than PHP signatures: the attributes and their parameters, the hooks Pollora fires, the configuration keys and the console commands. pollora-qa surface --update records them in api-surface.json, one line per entry:
"attribute:Pollora\\Attributes\\WpRestRoute($permissionCallback)": "Pollora\\Attributes\\WpRestRoute\\Permission|string|null, optional = NULL",
"hook:pollora/media/stored": "hook",
"config:media.disk": "key",
"command:pollora:make:block": "command"In CI, a pull request that changes the surface needs a label (QA-04): api-change when it only adds entries (a minor version), breaking when it removes or changes one, or adds a required parameter to an existing attribute (a major version, after a deprecation). The diff shows exactly what a release changes for its users. PHP signatures are compared with the latest tag by roave/backward-compatibility-check (QA-05).
vendor/bin/pollora-qa rules prints the catalogue, from resources/rules.php. Each rule is enforced (fails the gate), observed (reported only) or planned (not checked by this version yet).
An exception to a rule is written on the line it concerns, with its reason: // @phpstan-ignore <identifier> (reason) or // nosemgrep -- reason. Nothing is silenced without a trace.
This is phase 1 of the rollout: the harness measures every repository without blocking it. Integration tests against a real WordPress, adapter contract tests, mutation testing and performance budgets follow in the next phases.