# Guard Checklist Use this checklist for the guard reviewer. Canonical guard IDs live in `agent-system/checks/guard-catalog.json`. ## Architecture - `GR-CORE-001` no boundary violations against project layering - `GR-CORE-002` no direct bypass of shared factories/services where prohibited - `GR-CORE-003` request input contract is respected (requestInput(), no $_POST/$_GET/$_FILES/REQUEST_METHOD) - `GR-CORE-004` API json body contract is respected - `GR-CORE-008` no direct superglobal access in pages ($_SESSION, $_SERVER, $_COOKIE, $_ENV) - `GR-CORE-009` new Repository list methods use RepoQuery::sanitizeLimitOffset(); no unbounded SELECTs on large tables; maxLimit 100 not raised without justification - `GR-CORE-010` DB schema changes for existing installs shipped as idempotent SQL scripts in db/updates/; db/init/init.sql alone is not sufficient - `GR-CORE-011` new settings stored in DB settings table via settings gateway; config/settings.php is hot-path cache only, not primary storage - `GR-CORE-012` successful mutating POSTs respond with redirect (PRG); flash messages set before redirect via Flash::set() ## Security - `GR-CORE-005` auth and permission checks stay intact - `GR-CORE-006` tenant-scope checks stay intact - `GR-SEC-001` CSRF token verified on every POST endpoint before request body processing - `GR-SEC-002` no unredacted PII or secrets in logs and audit metadata - `GR-SEC-003` all SQL goes through Repository with prepared statements; no string-interpolated queries - `GR-SEC-004` no external CDN or remote asset loading; all JS/CSS/fonts must be vendored locally and served via assetVersion() - `GR-SEC-005` encryption only via lib/Support/Crypto.php (AES-256-GCM); no raw openssl_encrypt, no base64-as-encryption, no hand-rolled crypto - `GR-SEC-006` user-uploaded files stored under storage/{type}/{uuid}/ only; never written to web/; served via PHP controller with authz check; MIME + extension validated before storage ## Frontend and UX - `GR-UI-001` list initialization standard is preserved - `GR-UI-002` no legacy filter toggle markup introduced - `GR-UI-003` row interaction standard is preserved where applicable - `GR-UI-004` page size standard is preserved where applicable - `GR-UI-005` detail page standard is preserved where applicable - `GR-UI-006` no inline confirm hacks - `GR-UI-007` shared partial usage remains consistent (existing partials reused where applicable) - `GR-UI-016` template structure discipline: new pages use established layout system; blocks reused in ≥2 pages extracted as partial in templates/partials/ with naming app-{context}-{purpose}.phtml; no ad-hoc layout HTML in pages that bypasses the layout system - `GR-UI-008` template RBAC contract remains consistent - `GR-UI-009` no regression in a11y basics (labels, roles, keyboard focus) for touched flows - `GR-UI-013` a11y by design: new interactive components use semantic HTML, are keyboard-operable (Tab/Enter/Escape), use ARIA only where necessary, meet WCAG 2.1 AA contrast - `GR-UI-014` UI state completeness: new views/components define and implement loading, empty, error, and success states before implementation starts - `GR-UI-010` all user-visible strings in phtml views wrapped in t(); no hardcoded display strings - `GR-UI-015` new t() keys present in all language files (de + en) in the same merge; no key missing in any language file - `GR-UI-011` JS reuse-first: existing exports in web/js/core/ and web/js/components/ checked before adding a new function; no logic duplication from core modules - `GR-UI-012` CSS reuse-first: existing app-* classes and layer rules checked before writing new declarations; only additive overrides on top of shared components - `GR-UI-017` lifecycle runtime contract for migrated components is enforced (init(root, config) + destroy(), no component-level auto-init side effects, no legacy wrappers/init alias exports, cleanup of listeners/timers/observers, runtime config via page-config, page-level JS only via `web/js/pages/*` modules, host-bound components incl. tabs with `data-app-component` and root-strict selectors, global utilities only via explicit runtime-global registration, no project-specific custom `window.*` globals, namespaced UI storage without legacy fallback/sync paths) ## Testing - `GR-TEST-001` new or changed Service/Gateway logic has accompanying PHPUnit tests (happy path + at least one failure/edge case) in the same merge - `GR-TEST-002` new code uses constructor injection; no static side-effects, hidden global state, or untestable DB/HTTP calls outside Repository/Gateway abstractions ## Language and Style - `GR-LANG-001` PSR-4 namespace/directory alignment is intact (verified by QG-003) - `GR-LANG-002` PHP style passes composer cs:check without diff for touched files ## Quality Gates - `QG-001` to `QG-003` are run unless explicitly out of scope - `QG-004` fast structural checks reported when relevant - `QG-005` JS smoke performed for JS-touching changes; no new unhandled runtime errors - `QG-006` PHP style check run for any PHP-touching changes - `QG-007` composer-unused run periodically; any newly unused package flagged to reviewer References: - `tools/codex-skills/core-guardrails/references/boundaries-core.md` - `tools/codex-skills/core-guardrails/references/boundaries-ui.md` - `tools/codex-skills/core-guardrails/references/quality-gates.md` - `tools/codex-skills/starterkit-grid-standards/SKILL.md` - `tools/codex-skills/starterkit-php-style-ci/SKILL.md`