This repository follows the Pollora harness (profile framework, observe mode). The same gates run on your machine, in agent hooks and in CI; a pull request merges only when they pass.
composer qa:fastruns the fast gates on what you changed (style, static analysis, architecture, dependencies). It must pass.composer qaruns every gate, as CI does.vendor/bin/pollora-qa rules <ID>explains a rule quoted in a failure.
- Never edit
.harness.json,phpstan-baseline.neon,api-surface.json: they hold the thresholds. If one is wrong, stop and explain why to the user. - Never add
@phpstan-ignore, a baseline entry or anosemgrepcomment without a written reason on the same line. - Never weaken a test to make it pass, and never mark a test skipped to get a green run.
- Never break the public API (attributes, hooks fired, configuration keys, commands) in a minor version: deprecate first.
- A bug fix comes with a test that fails without the fix.
- Domain code depends on ports (interfaces), never on WordPress functions, Laravel or the Infrastructure layer.
- The common case of a public API needs no configuration; options are chained methods or named arguments.
- ARCH-01 Domain code imports neither Illuminate nor the Infrastructure or UI layers (Pest arch, G1)
- ARCH-02 Domain code calls no global WordPress function (PHPStan rule pollora.noWordPressCallInDomain, G1)
- ARCH-03 Application code depends on the Domain layer only (Pest arch, G1)
- ARCH-04 A core package requires neither illuminate/* nor laravel/*, unless listed in .harness.json (pollora-qa deps, G1)
- ARCH-05 The framework core references no third-party plugin (WooCommerce, ACF, Meta Box, WP Rocket) (Semgrep, G1)
- ARCH-06 Only integration packages, templates and projects depend on pollora/framework (pollora-qa deps, G1)
- ARCH-07 Every dependency used is declared, none declared is unused (composer-dependency-analyser, G1)
- ARCH-08 Attribute classes are final, readonly and declare their targets (Pest arch, G1)
- ARCH-09 declare(strict_types=1) in every file (Pest arch + Pint, G1)
- CONV-03 Laravel naming: ServiceProvider, Command, Exception, Repository, Factory suffixes (Pest arch, G1)
- CONV-04 Hooks fired by Pollora are named pollora//<event_snake_case> (pollora-qa surface, G2)
- CONV-05 Configuration lives under pollora.; env() is only called in config/ (Pest arch, G1)
- CONV-06 Commands are named pollora: or pollora:make- (pollora-qa surface, G2)
- CONV-07 Domain and Application code never calls app() or resolve(); it receives contracts (Pest arch, G1)
- CONV-10 One named exception per business case; never throw a bare \Exception (Semgrep, G1)
- CONV-11 Native types everywhere; PHPDoc only for generics, array shapes, @internal, @deprecated (PHPStan + Pest type coverage, G1)
- SEC-01 A REST route declared by attribute states its permission; a public route says so explicitly (Semgrep, G1)
- SEC-03 No $wpdb query built by interpolation without prepare() (Semgrep, G1)
- SEC-04 No unescaped Blade output {!! !!} outside a commented allowlist (Semgrep, G1)
- SEC-05 No unserialize, eval or extract (Semgrep, G1)
- SEC-08 No secret in the repository (gitleaks, G1)
- SEC-09 No dependency with a known vulnerability (composer audit, G1)
- QA-01 Ratchet: no metric gets worse (PHPStan level and baseline, coverage, mutation score) (pollora-qa ratchet, G2)
- QA-02 The harness files are protected: baseline, .harness.json and api-surface.json change only through a human (Agent hooks + CODEOWNERS, G0)
- QA-04 The public surface (attributes, hooks fired, configuration keys, commands) changes only with a label: api-change to add, breaking to remove or change (pollora-qa surface, G2)
- QA-05 No PHP signature breaks backward compatibility outside a major version (roave/backward-compatibility-check, G2)
- QA-03 A change to a core package keeps the framework green (Downstream job, G2)