refactor: relocate agent-system/ to .agents/ with 7-role workflow restructure
Moves the agent workflow system from agent-system/ to .agents/ (dotfile convention). Restructured from 5-role to 7-role pipeline: adds Analyst and splits Reviewer into Code Reviewer + Security Reviewer. Removes all old workflow run artifacts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
24
.agents/checks/acceptance-checklist.md
Normal file
24
.agents/checks/acceptance-checklist.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Acceptance Test Checklist
|
||||
|
||||
Use this checklist for the Acceptance Tester role.
|
||||
|
||||
## Scope
|
||||
- all in-scope items from `plan.json` are implemented
|
||||
- out-of-scope items are not silently introduced
|
||||
|
||||
## Behavior
|
||||
- each `SC-*` success criterion from `plan.json` is verifiably met
|
||||
- negative and edge paths behave as defined
|
||||
|
||||
## Regressions
|
||||
- existing flows still work after change
|
||||
- no critical UX break on key user paths
|
||||
|
||||
## Tests
|
||||
- every test listed in `plan.json tests[]` is implemented and passes (QG-001 green)
|
||||
- new Service/Gateway logic has at least one test (GR-TEST-001)
|
||||
|
||||
## Evidence
|
||||
- each criterion has explicit pass/fail evidence
|
||||
- each criterion check references the exact `SC-*` ID
|
||||
- fail findings include exact missing behavior
|
||||
159
.agents/checks/guard-catalog.json
Normal file
159
.agents/checks/guard-catalog.json
Normal file
@@ -0,0 +1,159 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"guards": [
|
||||
{
|
||||
"id": "GR-CORE-003",
|
||||
"area": "core",
|
||||
"reviewer": "code",
|
||||
"title": "Request input contract",
|
||||
"requirement": "MUST read input via requestInput() in pages and avoid superglobals for request data."
|
||||
},
|
||||
{
|
||||
"id": "GR-CORE-007",
|
||||
"area": "core",
|
||||
"reviewer": "code",
|
||||
"title": "OpenAPI sync",
|
||||
"requirement": "MUST update docs/openapi.yaml in the same merge when API endpoints change."
|
||||
},
|
||||
{
|
||||
"id": "GR-CORE-010",
|
||||
"area": "core",
|
||||
"reviewer": "code",
|
||||
"title": "Idempotent DB update scripts",
|
||||
"requirement": "Schema or data changes for existing installs MUST be shipped as idempotent SQL scripts in db/updates/ (IF NOT EXISTS, ON DUPLICATE KEY, guarded ALTER TABLE). db/init/init.sql alone is not sufficient."
|
||||
},
|
||||
{
|
||||
"id": "GR-CORE-011",
|
||||
"area": "core",
|
||||
"reviewer": "code",
|
||||
"title": "Settings in DB, not config files",
|
||||
"requirement": "New application settings MUST be stored in the settings DB table. config/settings.php is a partial hot-path cache only."
|
||||
},
|
||||
{
|
||||
"id": "GR-CORE-012",
|
||||
"area": "core",
|
||||
"reviewer": "code",
|
||||
"title": "POST-Redirect-GET",
|
||||
"requirement": "Actions that successfully mutate state MUST respond with a redirect (PRG pattern). Flash messages set before redirect via Flash::set()."
|
||||
},
|
||||
{
|
||||
"id": "GR-TEST-001",
|
||||
"area": "test",
|
||||
"reviewer": "code",
|
||||
"title": "Tests ship with new logic",
|
||||
"requirement": "New or changed business logic in lib/Service/ MUST be accompanied by PHPUnit tests covering the happy path and at least one failure or edge case. No new public method in a Service or Gateway without a test."
|
||||
},
|
||||
{
|
||||
"id": "GR-TEST-002",
|
||||
"area": "test",
|
||||
"reviewer": "code",
|
||||
"title": "Code must be testable",
|
||||
"requirement": "New code MUST use constructor injection. MUST NOT introduce static side-effects in constructors, hidden global state, or direct DB/HTTP calls outside Repository/Gateway abstractions."
|
||||
},
|
||||
{
|
||||
"id": "GR-UI-014",
|
||||
"area": "ui",
|
||||
"reviewer": "code",
|
||||
"title": "UI state completeness",
|
||||
"requirement": "New user-facing views or components MUST handle four states: loading, empty, error, success. All four defined in plan before implementation. Not required for small fixes to existing UI."
|
||||
},
|
||||
{
|
||||
"id": "GR-UI-LIST",
|
||||
"area": "ui",
|
||||
"reviewer": "code",
|
||||
"title": "List and grid standards",
|
||||
"requirement": "Lists MUST preserve row action column plus enter/dblclick fallback behavior. Page size options and URL/localStorage/default precedence MUST be maintained. New lists MUST use initStandardListPage()."
|
||||
},
|
||||
{
|
||||
"id": "GR-UI-DETAIL",
|
||||
"area": "ui",
|
||||
"reviewer": "code",
|
||||
"title": "Detail page standards",
|
||||
"requirement": "MUST use standard detail page contracts for dirty-state and actions. MUST NOT use inline confirm handlers on standardized flows. MUST use shared list/detail partials for standardized UI blocks. New pages MUST use the established layout system. Blocks reused in 2+ pages MUST be extracted as partials (app-{context}-{purpose}.phtml)."
|
||||
},
|
||||
{
|
||||
"id": "GR-UI-A11Y",
|
||||
"area": "ui",
|
||||
"reviewer": "code",
|
||||
"title": "Accessibility",
|
||||
"requirement": "MUST NOT regress a11y basics (labels, roles, keyboard focus) on touched flows. New interactive components MUST use semantic HTML, be keyboard-operable (Tab/Enter/Escape), use ARIA only where necessary, and meet WCAG 2.1 AA contrast."
|
||||
},
|
||||
{
|
||||
"id": "GR-UI-I18N",
|
||||
"area": "ui",
|
||||
"reviewer": "code",
|
||||
"title": "Internationalization completeness",
|
||||
"requirement": "All user-visible strings in phtml views MUST use t('key'). Every new t() key MUST be present in ALL language files (i18n/default_de.json and i18n/default_en.json) in the same merge."
|
||||
},
|
||||
{
|
||||
"id": "GR-UI-REUSE",
|
||||
"area": "ui",
|
||||
"reviewer": "code",
|
||||
"title": "Reuse-first (JS + CSS)",
|
||||
"requirement": "MUST check web/js/core/ and web/js/components/ for existing exports before adding new functions. MUST check existing CSS layers and app-* classes before writing new rules. No duplication of logic from core modules."
|
||||
},
|
||||
{
|
||||
"id": "GR-SEC-001",
|
||||
"area": "security",
|
||||
"reviewer": "security",
|
||||
"title": "CSRF on POST",
|
||||
"requirement": "MUST verify CSRF token on every POST endpoint in pages before processing the request body."
|
||||
},
|
||||
{
|
||||
"id": "GR-SEC-002",
|
||||
"area": "security",
|
||||
"reviewer": "security",
|
||||
"title": "No PII/secrets in logs",
|
||||
"requirement": "MUST NOT write PII (email, names, UUIDs) or secrets (tokens, passwords) to logs or audit metadata without prior redaction."
|
||||
},
|
||||
{
|
||||
"id": "GR-SEC-003",
|
||||
"area": "security",
|
||||
"reviewer": "security",
|
||||
"title": "SQL via prepared statements only",
|
||||
"requirement": "MUST NOT build SQL strings with user-controlled input. All queries MUST go through Repository classes using prepared statements."
|
||||
},
|
||||
{
|
||||
"id": "GR-SEC-004",
|
||||
"area": "security",
|
||||
"reviewer": "security",
|
||||
"title": "No external CDN/remote assets",
|
||||
"requirement": "MUST NOT load JS, CSS, fonts from external CDNs or remote URLs. Third-party libraries MUST be vendored locally and served via assetVersion()."
|
||||
},
|
||||
{
|
||||
"id": "GR-SEC-005",
|
||||
"area": "security",
|
||||
"reviewer": "security",
|
||||
"title": "Encryption via Crypto only",
|
||||
"requirement": "Encryption/decryption MUST use lib/Support/Crypto.php (AES-256-GCM). No raw openssl_encrypt, no base64 as encryption, no hand-rolled crypto."
|
||||
},
|
||||
{
|
||||
"id": "GR-SEC-006",
|
||||
"area": "security",
|
||||
"reviewer": "security",
|
||||
"title": "File uploads in storage/ only",
|
||||
"requirement": "User-uploaded files MUST be stored under storage/ with non-guessable identifiers. MUST NOT be written to web/. MUST be served via PHP controller with authz. MUST validate MIME + extension before storing."
|
||||
},
|
||||
{
|
||||
"id": "GR-SEC-007",
|
||||
"area": "security",
|
||||
"reviewer": "security",
|
||||
"title": "API must not start sessions",
|
||||
"requirement": "API requests (api/ prefix) MUST NOT trigger Session::start(), remember-me cookie handling, or session timeout redirects."
|
||||
},
|
||||
{
|
||||
"id": "GR-SEC-008",
|
||||
"area": "security",
|
||||
"reviewer": "security",
|
||||
"title": "Server-side authorization",
|
||||
"requirement": "MUST enforce authorization server-side in actions and services. UI-only permission checks are insufficient."
|
||||
},
|
||||
{
|
||||
"id": "GR-SEC-009",
|
||||
"area": "security",
|
||||
"reviewer": "security",
|
||||
"title": "Server-side tenant scope",
|
||||
"requirement": "MUST enforce tenant scope server-side. Every query touching tenant-scoped data MUST filter by tenant_id. No cross-tenant data leakage."
|
||||
}
|
||||
]
|
||||
}
|
||||
45
.agents/checks/guard-checklist.md
Normal file
45
.agents/checks/guard-checklist.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Code Review Checklist
|
||||
|
||||
Use this checklist for the Code Reviewer role.
|
||||
Guard IDs live in `.agents/checks/guard-catalog.json` (guards where `reviewer` = `code`).
|
||||
|
||||
## Architecture & Conventions
|
||||
- `GR-CORE-003` request input via requestInput(); no $_POST/$_GET/$_FILES
|
||||
- `GR-CORE-007` OpenAPI updated when API endpoints changed
|
||||
- `GR-CORE-010` DB schema changes shipped as idempotent scripts in db/updates/
|
||||
- `GR-CORE-011` new settings in DB settings table, not config files
|
||||
- `GR-CORE-012` successful mutating POSTs use PRG pattern; flash before redirect
|
||||
|
||||
## Testing
|
||||
- `GR-TEST-001` new/changed Service/Gateway logic has PHPUnit tests (happy + edge case)
|
||||
- `GR-TEST-002` new code uses constructor injection; no hidden global state
|
||||
|
||||
## UI (skip if backend-only)
|
||||
- `GR-UI-014` new views/components handle loading, empty, error, success states
|
||||
- `GR-UI-LIST` list/grid standards preserved (row actions, page size, initStandardListPage)
|
||||
- `GR-UI-DETAIL` detail page contracts, shared partials, no inline confirm, layout system
|
||||
- `GR-UI-A11Y` no a11y regression; new components use semantic HTML, keyboard-operable
|
||||
- `GR-UI-I18N` all visible text uses t(); keys present in all language files
|
||||
- `GR-UI-REUSE` existing JS/CSS checked before adding new functions/rules
|
||||
|
||||
## Quality Gates
|
||||
- `QG-001` to `QG-003` are run unless explicitly out of scope
|
||||
- `QG-004` structural checks reported when relevant
|
||||
- `QG-005` JS smoke for JS-touching changes
|
||||
- `QG-006` PHP style check for PHP-touching changes
|
||||
|
||||
# Security Review Checklist
|
||||
|
||||
Use this checklist for the Security Reviewer role.
|
||||
Guard IDs live in `.agents/checks/guard-catalog.json` (guards where `reviewer` = `security`).
|
||||
|
||||
## Security
|
||||
- `GR-SEC-001` CSRF token verified on every POST before processing
|
||||
- `GR-SEC-002` no PII or secrets in logs/audit metadata
|
||||
- `GR-SEC-003` all SQL via Repository with prepared statements
|
||||
- `GR-SEC-004` no external CDN or remote asset loading
|
||||
- `GR-SEC-005` encryption only via lib/Support/Crypto.php
|
||||
- `GR-SEC-006` file uploads in storage/ only; authz-gated serving; MIME validated
|
||||
- `GR-SEC-007` API requests do not start sessions
|
||||
- `GR-SEC-008` authorization enforced server-side
|
||||
- `GR-SEC-009` tenant scope enforced server-side; tenant_id filtering on all scoped queries
|
||||
62
.agents/checks/quality-gates.json
Normal file
62
.agents/checks/quality-gates.json
Normal file
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"source": ".agents/skills/core-guardrails/references/quality-gates.md",
|
||||
"gates": [
|
||||
{
|
||||
"id": "QG-001",
|
||||
"type": "mandatory",
|
||||
"name": "PHPUnit Full",
|
||||
"command": "docker compose exec php vendor/bin/phpunit"
|
||||
},
|
||||
{
|
||||
"id": "QG-002",
|
||||
"type": "mandatory",
|
||||
"name": "PHPStan",
|
||||
"command": "docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress"
|
||||
},
|
||||
{
|
||||
"id": "QG-003",
|
||||
"type": "mandatory",
|
||||
"name": "Architecture Core Contract",
|
||||
"command": "docker compose exec php vendor/bin/phpunit tests/Architecture/CoreStarterkitContractTest.php"
|
||||
},
|
||||
{
|
||||
"id": "QG-004",
|
||||
"type": "fast",
|
||||
"name": "Structural rg checks",
|
||||
"command": "(rg 'new\\s+[^\\s(]+Factory\\(' lib/Service || true) | wc -l\n(rg --glob '!**/*Factory.php' 'new\\s+[^\\s(]+(Service|Gateway|Repository)\\(' lib/Service || true) | wc -l\n(rg \"\\b(accessServicesFactory|directoryServicesFactory|userServicesFactory|authServicesFactory|tenantServicesFactory|settingServicesFactory|userRepositoryFactory|authRepositoryFactory|authGatewayFactory)\\(\" pages lib templates web || true) | wc -l\n(rg -n 'new\\s+[^\\s(]+(Service|Gateway|Repository)\\(' pages -g '*.php' || true) | wc -l\n(rg -n '\\bDB::' pages -g '*.php' || true) | wc -l\n(rg -n 'app\\([^\\n]*Factory::class\\)->create' pages/admin -g '*.php' || true) | wc -l\n(rg -n 'Factory::class' pages/admin -g '*.php' || true) | wc -l\n(rg -n 'ApiResponse::readJsonBody\\(' pages/api/v1 -g '*.php' || true) | wc -l"
|
||||
},
|
||||
{
|
||||
"id": "QG-005",
|
||||
"type": "manual",
|
||||
"name": "JS smoke",
|
||||
"command": "Browser smoke test with DevTools console; expect no new JS errors."
|
||||
},
|
||||
{
|
||||
"id": "QG-006",
|
||||
"type": "fast",
|
||||
"name": "PHP Style Check",
|
||||
"command": "docker compose exec php composer cs:check"
|
||||
},
|
||||
{
|
||||
"id": "QG-007",
|
||||
"type": "periodic",
|
||||
"name": "Unused Composer packages",
|
||||
"command": "docker compose exec php vendor/bin/composer-unused",
|
||||
"note": "Run periodically (not per-merge). Flag any newly unused package to the reviewer."
|
||||
},
|
||||
{
|
||||
"id": "QG-008",
|
||||
"type": "fast",
|
||||
"name": "Docs link integrity",
|
||||
"command": "bin/docs-link-check.sh",
|
||||
"note": "Default scanner excludes .agents/runs/** to avoid historical artifact false positives."
|
||||
},
|
||||
{
|
||||
"id": "QG-009",
|
||||
"type": "fast",
|
||||
"name": "Codex skills sync",
|
||||
"command": "bin/codex-skills-sync.sh --check"
|
||||
}
|
||||
]
|
||||
}
|
||||
82
.agents/contracts/analyst.schema.json
Normal file
82
.agents/contracts/analyst.schema.json
Normal file
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "Analyst Output",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"task_id",
|
||||
"issue_summary",
|
||||
"affected_layers",
|
||||
"affected_files",
|
||||
"existing_patterns",
|
||||
"related_tests",
|
||||
"security_surface",
|
||||
"assumptions",
|
||||
"risks_discovered"
|
||||
],
|
||||
"properties": {
|
||||
"task_id": { "type": "string", "minLength": 1 },
|
||||
"issue_summary": { "type": "string", "minLength": 1 },
|
||||
"affected_layers": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": ["Repository", "Service", "pages", "templates", "web/js", "web/css", "modules", "config", "db", "bin"]
|
||||
}
|
||||
},
|
||||
"affected_files": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["path", "role"],
|
||||
"properties": {
|
||||
"path": { "type": "string", "minLength": 1 },
|
||||
"role": { "type": "string", "minLength": 1 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"existing_patterns": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Partials, helpers, services, or conventions already in use for this area."
|
||||
},
|
||||
"related_tests": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Existing test files relevant to the change."
|
||||
},
|
||||
"security_surface": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"authz_relevant": { "type": "boolean" },
|
||||
"tenant_scope_relevant": { "type": "boolean" },
|
||||
"input_handling": { "type": "boolean" },
|
||||
"crypto_relevant": { "type": "boolean" },
|
||||
"file_upload_relevant": { "type": "boolean" },
|
||||
"notes": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"module_context": {
|
||||
"type": "object",
|
||||
"description": "Present only when a module is involved.",
|
||||
"properties": {
|
||||
"module_id": { "type": "string" },
|
||||
"active": { "type": "boolean" },
|
||||
"manifest_declarations": { "type": "array", "items": { "type": "string" } }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"assumptions": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Ambiguities the Planner must resolve."
|
||||
},
|
||||
"risks_discovered": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
97
.agents/contracts/executor.schema.json
Normal file
97
.agents/contracts/executor.schema.json
Normal file
@@ -0,0 +1,97 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "Executor Output",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"task_id",
|
||||
"plan_ref",
|
||||
"status",
|
||||
"changed_files",
|
||||
"guard_evidence",
|
||||
"commands",
|
||||
"quality_gate_results",
|
||||
"test_results",
|
||||
"open_items"
|
||||
],
|
||||
"properties": {
|
||||
"task_id": { "type": "string", "minLength": 1 },
|
||||
"plan_ref": { "type": "string", "minLength": 1 },
|
||||
"status": { "type": "string", "enum": ["done", "blocked"] },
|
||||
"changed_files": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["path", "summary"],
|
||||
"properties": {
|
||||
"path": { "type": "string", "minLength": 1 },
|
||||
"summary": { "type": "string", "minLength": 1 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"guard_evidence": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["guard_id", "status", "evidence"],
|
||||
"properties": {
|
||||
"guard_id": {
|
||||
"type": "string",
|
||||
"pattern": "^GR-(CORE|TEST|UI|SEC)-[A-Z0-9]{3,}$"
|
||||
},
|
||||
"status": { "type": "string", "enum": ["pass", "fail", "n/a"] },
|
||||
"evidence": { "type": "string", "minLength": 1 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["cmd", "result"],
|
||||
"properties": {
|
||||
"cmd": { "type": "string", "minLength": 1 },
|
||||
"result": { "type": "string", "enum": ["pass", "fail", "skipped"] }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"quality_gate_results": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["gate_id", "result"],
|
||||
"properties": {
|
||||
"gate_id": {
|
||||
"type": "string",
|
||||
"pattern": "^QG-[0-9]{3}$"
|
||||
},
|
||||
"result": { "type": "string", "enum": ["pass", "fail", "skipped"] },
|
||||
"notes": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"test_results": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["name", "result"],
|
||||
"properties": {
|
||||
"name": { "type": "string", "minLength": 1 },
|
||||
"result": { "type": "string", "enum": ["pass", "fail", "skipped"] },
|
||||
"notes": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"open_items": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
98
.agents/contracts/finalizer.schema.json
Normal file
98
.agents/contracts/finalizer.schema.json
Normal file
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "Finalizer Output",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"task_id",
|
||||
"ready_to_finalize",
|
||||
"code_review",
|
||||
"security_review",
|
||||
"acceptance_review",
|
||||
"ci_status",
|
||||
"final_action"
|
||||
],
|
||||
"properties": {
|
||||
"task_id": { "type": "string", "minLength": 1 },
|
||||
"ready_to_finalize": { "type": "boolean" },
|
||||
"code_review": { "type": "string", "enum": ["pass", "fail"] },
|
||||
"security_review": { "type": "string", "enum": ["pass", "fail"] },
|
||||
"acceptance_review": { "type": "string", "enum": ["pass", "fail"] },
|
||||
"ci_status": { "type": "string", "enum": ["pass", "fail", "unknown"] },
|
||||
"final_action": { "type": "string", "enum": ["commit", "merge", "hold"] },
|
||||
"hold_reason": { "type": "string", "minLength": 1 },
|
||||
"commit_message": { "type": "string" },
|
||||
"notes": { "type": "string" }
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"if": {
|
||||
"properties": { "final_action": { "const": "hold" } },
|
||||
"required": ["final_action"]
|
||||
},
|
||||
"then": {
|
||||
"required": ["hold_reason"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": { "final_action": { "enum": ["commit", "merge"] } },
|
||||
"required": ["final_action"]
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"ready_to_finalize": { "const": true },
|
||||
"code_review": { "const": "pass" },
|
||||
"security_review": { "const": "pass" },
|
||||
"acceptance_review": { "const": "pass" },
|
||||
"ci_status": { "const": "pass" }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": { "ci_status": { "enum": ["fail", "unknown"] } },
|
||||
"required": ["ci_status"]
|
||||
},
|
||||
"then": {
|
||||
"properties": { "final_action": { "const": "hold" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": { "code_review": { "const": "fail" } },
|
||||
"required": ["code_review"]
|
||||
},
|
||||
"then": {
|
||||
"properties": { "final_action": { "const": "hold" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": { "security_review": { "const": "fail" } },
|
||||
"required": ["security_review"]
|
||||
},
|
||||
"then": {
|
||||
"properties": { "final_action": { "const": "hold" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": { "acceptance_review": { "const": "fail" } },
|
||||
"required": ["acceptance_review"]
|
||||
},
|
||||
"then": {
|
||||
"properties": { "final_action": { "const": "hold" } }
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": { "ready_to_finalize": { "const": false } },
|
||||
"required": ["ready_to_finalize"]
|
||||
},
|
||||
"then": {
|
||||
"properties": { "final_action": { "const": "hold" } }
|
||||
}
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
142
.agents/contracts/planner.schema.json
Normal file
142
.agents/contracts/planner.schema.json
Normal file
@@ -0,0 +1,142 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "Planner Output",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"task_id",
|
||||
"analysis_ref",
|
||||
"summary",
|
||||
"scope",
|
||||
"guardrails",
|
||||
"success_criteria",
|
||||
"implementation_steps",
|
||||
"tests",
|
||||
"acceptance_checks",
|
||||
"risks"
|
||||
],
|
||||
"properties": {
|
||||
"task_id": { "type": "string", "minLength": 1 },
|
||||
"analysis_ref": { "type": "string", "minLength": 1, "description": "Path to analysis.json" },
|
||||
"summary": { "type": "string", "minLength": 1 },
|
||||
"assumptions": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
},
|
||||
"scope": {
|
||||
"type": "object",
|
||||
"required": ["in", "out"],
|
||||
"properties": {
|
||||
"in": { "type": "array", "items": { "type": "string" } },
|
||||
"out": { "type": "array", "items": { "type": "string" } }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"guardrails": {
|
||||
"type": "object",
|
||||
"required": ["required_guard_ids", "required_quality_gate_ids"],
|
||||
"properties": {
|
||||
"required_guard_ids": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^GR-(CORE|TEST|UI|SEC)-[A-Z0-9]{3,}$"
|
||||
}
|
||||
},
|
||||
"required_quality_gate_ids": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^QG-[0-9]{3}$"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"success_criteria": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["id", "criterion"],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^SC-[0-9]{3}$"
|
||||
},
|
||||
"criterion": { "type": "string", "minLength": 1 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"implementation_steps": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["id", "title", "description", "guard_refs"],
|
||||
"properties": {
|
||||
"id": { "type": "string", "minLength": 1 },
|
||||
"title": { "type": "string", "minLength": 1 },
|
||||
"description": { "type": "string", "minLength": 1 },
|
||||
"guard_refs": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^GR-(CORE|TEST|UI|SEC)-[A-Z0-9]{3,}$"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"tests": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": { "type": "string" }
|
||||
},
|
||||
"acceptance_checks": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": { "type": "string" }
|
||||
},
|
||||
"ux_notes": {
|
||||
"type": "object",
|
||||
"description": "Required for tasks touching UI. Leave fields as empty arrays if not applicable.",
|
||||
"properties": {
|
||||
"affected_patterns": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
},
|
||||
"ui_states_required": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": ["loading", "empty", "error", "success"]
|
||||
}
|
||||
},
|
||||
"a11y_touchpoints": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"risks": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["risk", "mitigation"],
|
||||
"properties": {
|
||||
"risk": { "type": "string", "minLength": 1 },
|
||||
"mitigation": { "type": "string", "minLength": 1 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
81
.agents/contracts/reviewer-acceptance.schema.json
Normal file
81
.agents/contracts/reviewer-acceptance.schema.json
Normal file
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "Acceptance Tester Output",
|
||||
"type": "object",
|
||||
"required": ["task_id", "verdict", "checked_criterion_ids", "checks"],
|
||||
"properties": {
|
||||
"task_id": { "type": "string", "minLength": 1 },
|
||||
"verdict": { "type": "string", "enum": ["pass", "fail"] },
|
||||
"checked_criterion_ids": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^SC-[0-9]{3}$"
|
||||
}
|
||||
},
|
||||
"checks": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["criterion_id", "criterion", "result", "evidence"],
|
||||
"properties": {
|
||||
"criterion_id": {
|
||||
"type": "string",
|
||||
"pattern": "^SC-[0-9]{3}$"
|
||||
},
|
||||
"criterion": { "type": "string", "minLength": 1 },
|
||||
"result": { "type": "string", "enum": ["pass", "fail"] },
|
||||
"evidence": { "type": "string", "minLength": 1 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"missing_or_wrong": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"if": {
|
||||
"properties": { "verdict": { "const": "pass" } },
|
||||
"required": ["verdict"]
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"checks": {
|
||||
"not": {
|
||||
"contains": {
|
||||
"type": "object",
|
||||
"properties": { "result": { "const": "fail" } },
|
||||
"required": ["result"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": { "verdict": { "const": "fail" } },
|
||||
"required": ["verdict"]
|
||||
},
|
||||
"then": {
|
||||
"required": ["missing_or_wrong"],
|
||||
"properties": {
|
||||
"missing_or_wrong": { "type": "array", "minItems": 1 },
|
||||
"checks": {
|
||||
"contains": {
|
||||
"type": "object",
|
||||
"properties": { "result": { "const": "fail" } },
|
||||
"required": ["result"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
46
.agents/contracts/reviewer-code.schema.json
Normal file
46
.agents/contracts/reviewer-code.schema.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "Code Reviewer Output",
|
||||
"type": "object",
|
||||
"required": ["task_id", "verdict", "checked_guard_ids", "checked_quality_gate_ids", "findings"],
|
||||
"properties": {
|
||||
"task_id": { "type": "string", "minLength": 1 },
|
||||
"verdict": { "type": "string", "enum": ["pass", "fail"] },
|
||||
"checked_guard_ids": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^GR-(CORE|TEST|UI)-[A-Z0-9]{3,}$"
|
||||
}
|
||||
},
|
||||
"checked_quality_gate_ids": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^QG-[0-9]{3}$"
|
||||
}
|
||||
},
|
||||
"findings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["id", "severity", "rule_ref", "summary", "file"],
|
||||
"properties": {
|
||||
"id": { "type": "string", "minLength": 1 },
|
||||
"severity": { "type": "string", "enum": ["low", "medium", "high", "critical"] },
|
||||
"rule_ref": {
|
||||
"type": "string",
|
||||
"pattern": "^(GR-(CORE|TEST|UI)-[A-Z0-9]{3,}|QG-[0-9]{3})$"
|
||||
},
|
||||
"summary": { "type": "string", "minLength": 1 },
|
||||
"file": { "type": "string", "minLength": 1 },
|
||||
"fix_required": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
61
.agents/contracts/reviewer-security.schema.json
Normal file
61
.agents/contracts/reviewer-security.schema.json
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "Security Reviewer Output",
|
||||
"type": "object",
|
||||
"required": ["task_id", "verdict", "checked_guard_ids", "findings"],
|
||||
"properties": {
|
||||
"task_id": { "type": "string", "minLength": 1 },
|
||||
"verdict": { "type": "string", "enum": ["pass", "fail"] },
|
||||
"checked_guard_ids": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^GR-SEC-[0-9]{3}$"
|
||||
}
|
||||
},
|
||||
"findings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["id", "severity", "rule_ref", "summary", "file"],
|
||||
"properties": {
|
||||
"id": { "type": "string", "minLength": 1 },
|
||||
"severity": {
|
||||
"type": "string",
|
||||
"enum": ["low", "medium", "high", "critical"],
|
||||
"description": "critical=exploitable in prod, high=likely exploitable, medium=defense-in-depth gap, low=minor hardening"
|
||||
},
|
||||
"rule_ref": {
|
||||
"type": "string",
|
||||
"pattern": "^GR-SEC-[0-9]{3}$"
|
||||
},
|
||||
"summary": { "type": "string", "minLength": 1 },
|
||||
"file": { "type": "string", "minLength": 1 },
|
||||
"line_range": { "type": "string", "description": "e.g. '42-58'" },
|
||||
"fix_required": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"findings": {
|
||||
"contains": {
|
||||
"type": "object",
|
||||
"properties": { "severity": { "enum": ["critical", "high"] } },
|
||||
"required": ["severity"]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": { "verdict": { "const": "fail" } }
|
||||
}
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
24
.agents/prompts/analyst.md
Normal file
24
.agents/prompts/analyst.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Analyst Prompt Baseline
|
||||
|
||||
Goal:
|
||||
- triage an issue or feature request by reading the codebase and producing a context brief for the Planner
|
||||
|
||||
Input:
|
||||
- issue description or feature request (free-form)
|
||||
|
||||
Required actions:
|
||||
- identify affected layers (Repository, Service, pages, templates, web/js, web/css, modules)
|
||||
- identify affected files and existing patterns (partials, helpers, services, repositories)
|
||||
- check for related existing tests
|
||||
- identify security surface (authz, tenant scope, input handling, crypto, file uploads)
|
||||
- note any risks or constraints discovered during exploration
|
||||
|
||||
Output:
|
||||
- valid JSON by `.agents/contracts/analyst.schema.json`
|
||||
|
||||
Rules:
|
||||
- DO NOT propose solutions — only gather and structure context
|
||||
- list concrete file paths, not vague layer references
|
||||
- if the issue is ambiguous, list assumptions that the Planner must resolve
|
||||
- if a module is involved, verify it is active and note its manifest declarations
|
||||
- keep the brief factual — no opinions on priority or effort
|
||||
21
.agents/prompts/executor.md
Normal file
21
.agents/prompts/executor.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Executor Prompt Baseline
|
||||
|
||||
Goal:
|
||||
- implement the approved plan with minimal scope drift
|
||||
|
||||
Input:
|
||||
- `plan.json` from Planner
|
||||
|
||||
Required references:
|
||||
- `.agents/checks/guard-catalog.json`
|
||||
- `.agents/checks/quality-gates.json`
|
||||
|
||||
Output:
|
||||
- valid JSON by `.agents/contracts/executor.schema.json`
|
||||
|
||||
Rules:
|
||||
- only implement items in plan scope
|
||||
- run relevant quality gates and include results
|
||||
- provide guard evidence for each required guard ID
|
||||
- list each changed file with a short reason
|
||||
- if blocked, set status to `blocked` and list exact blockers
|
||||
18
.agents/prompts/finalizer.md
Normal file
18
.agents/prompts/finalizer.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Finalizer Prompt Baseline
|
||||
|
||||
Goal:
|
||||
- finalize only when all three reviews pass and quality gates are green
|
||||
|
||||
Input:
|
||||
- `execution-report.json`
|
||||
- `review-code.json`
|
||||
- `review-security.json`
|
||||
- `review-acceptance.json`
|
||||
|
||||
Output:
|
||||
- valid JSON by `.agents/contracts/finalizer.schema.json`
|
||||
|
||||
Rules:
|
||||
- do not finalize if any reviewer verdict is `fail`
|
||||
- do not finalize unless `code_review=pass`, `security_review=pass`, `acceptance_review=pass`, and `ci_status=pass`
|
||||
- set `final_action` to `hold` and populate `hold_reason` whenever action is `hold`
|
||||
29
.agents/prompts/planner.md
Normal file
29
.agents/prompts/planner.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Planner Prompt Baseline
|
||||
|
||||
Goal:
|
||||
- transform the analysis brief into a decision-complete implementation plan
|
||||
|
||||
Input:
|
||||
- `analysis.json` from Analyst
|
||||
|
||||
Required references:
|
||||
- `.agents/checks/guard-catalog.json`
|
||||
- `.agents/checks/quality-gates.json`
|
||||
|
||||
Output:
|
||||
- valid JSON by `.agents/contracts/planner.schema.json`
|
||||
|
||||
Rules:
|
||||
- define explicit in-scope and out-of-scope
|
||||
- define measurable success criteria with stable IDs (`SC-001`, `SC-002`, ...)
|
||||
- select required guard IDs from guard catalog (code reviewer guards + security reviewer guards)
|
||||
- select required quality gate IDs from quality gates
|
||||
- include at least one risk with mitigation
|
||||
- keep implementation steps actionable and ordered
|
||||
- reference concrete file paths from the analysis brief — do not re-explore the codebase
|
||||
|
||||
UI task rules (apply when the task touches templates, pages/*.phtml, or web/js|css):
|
||||
- populate `ux_notes.affected_patterns`: list every existing UI pattern or partial being touched
|
||||
- populate `ux_notes.ui_states_required`: declare loading, empty, error, success states (GR-UI-014); omit only with explicit justification
|
||||
- populate `ux_notes.a11y_touchpoints`: list every new interactive element (GR-UI-A11Y)
|
||||
- if any `ux_notes` field is not applicable, set it to `[]` — do not omit the field
|
||||
22
.agents/prompts/reviewer-acceptance.md
Normal file
22
.agents/prompts/reviewer-acceptance.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Acceptance Tester Prompt Baseline
|
||||
|
||||
Goal:
|
||||
- verify the feature or fix is implemented exactly as requested
|
||||
|
||||
Input:
|
||||
- code diff
|
||||
- `plan.json`
|
||||
- `execution-report.json`
|
||||
|
||||
Required references:
|
||||
- `.agents/checks/acceptance-checklist.md`
|
||||
|
||||
Output:
|
||||
- valid JSON by `.agents/contracts/reviewer-acceptance.schema.json`
|
||||
|
||||
Rules:
|
||||
- evaluate each `plan.json` success criterion by its `SC-*` ID
|
||||
- include evidence for pass/fail checks
|
||||
- return `checked_criterion_ids` and per-check `criterion_id` values that match the plan
|
||||
- list missing behavior explicitly when verdict is `fail`
|
||||
- verify no out-of-scope changes were silently introduced
|
||||
37
.agents/prompts/reviewer-code.md
Normal file
37
.agents/prompts/reviewer-code.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Code Reviewer Prompt Baseline
|
||||
|
||||
Goal:
|
||||
- verify code quality, architecture compliance, and convention adherence
|
||||
|
||||
Input:
|
||||
- code diff
|
||||
- `execution-report.json`
|
||||
- `plan.json`
|
||||
|
||||
Required references:
|
||||
- `.agents/checks/guard-catalog.json` (guards where `reviewer` = `code`)
|
||||
- `.agents/checks/quality-gates.json`
|
||||
|
||||
Output:
|
||||
- valid JSON by `.agents/contracts/reviewer-code.schema.json`
|
||||
|
||||
Scope — verify these guards:
|
||||
- GR-CORE-003: request input contract
|
||||
- GR-CORE-007: OpenAPI sync (if API touched)
|
||||
- GR-CORE-010: idempotent DB scripts (if schema touched)
|
||||
- GR-CORE-011: settings in DB (if settings added)
|
||||
- GR-CORE-012: PRG pattern (if POST actions added/changed)
|
||||
- GR-TEST-001: tests ship with new logic
|
||||
- GR-TEST-002: code is testable
|
||||
- GR-UI-014: UI state completeness (if UI touched)
|
||||
- GR-UI-LIST: list/grid standards (if lists touched)
|
||||
- GR-UI-DETAIL: detail page standards (if detail pages touched)
|
||||
- GR-UI-A11Y: accessibility (if UI touched)
|
||||
- GR-UI-I18N: i18n completeness (if visible text touched)
|
||||
- GR-UI-REUSE: reuse-first (if JS/CSS added)
|
||||
|
||||
Rules:
|
||||
- findings MUST reference a guard or gate ID
|
||||
- findings MUST include file path
|
||||
- use `fail` only when changes are required before finalize
|
||||
- skip guards not relevant to the change (e.g. skip UI guards for backend-only changes)
|
||||
34
.agents/prompts/reviewer-security.md
Normal file
34
.agents/prompts/reviewer-security.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Security Reviewer Prompt Baseline
|
||||
|
||||
Goal:
|
||||
- verify the change does not introduce security vulnerabilities or weaken existing protections
|
||||
|
||||
Input:
|
||||
- code diff
|
||||
- `execution-report.json`
|
||||
- `plan.json`
|
||||
|
||||
Required references:
|
||||
- `.agents/checks/guard-catalog.json` (guards where `reviewer` = `security`)
|
||||
|
||||
Output:
|
||||
- valid JSON by `.agents/contracts/reviewer-security.schema.json`
|
||||
|
||||
Scope — verify these guards:
|
||||
- GR-SEC-001: CSRF token on POST
|
||||
- GR-SEC-002: no PII/secrets in logs or audit metadata
|
||||
- GR-SEC-003: SQL via prepared statements only
|
||||
- GR-SEC-004: no external CDN or remote asset loading
|
||||
- GR-SEC-005: encryption only via Crypto.php
|
||||
- GR-SEC-006: file uploads stored in storage/ only
|
||||
- GR-SEC-007: API must not start sessions
|
||||
- GR-SEC-008: server-side authorization enforced
|
||||
- GR-SEC-009: server-side tenant scope enforced
|
||||
|
||||
Rules:
|
||||
- findings MUST reference a GR-SEC-* guard ID
|
||||
- findings MUST include file path and line range where possible
|
||||
- severity MUST reflect actual exploitability: `critical` = exploitable in production, `high` = likely exploitable, `medium` = defense-in-depth gap, `low` = minor hardening
|
||||
- use `fail` verdict for any `critical` or `high` finding
|
||||
- skip guards not relevant to the change (e.g. skip GR-SEC-005 if no crypto touched)
|
||||
- for multi-tenant data flows, trace the query path from action → service → repository and verify tenant_id filtering at every level
|
||||
1
.agents/runs/.gitkeep
Normal file
1
.agents/runs/.gitkeep
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
42
.agents/skills/core-guardrails/SKILL.md
Normal file
42
.agents/skills/core-guardrails/SKILL.md
Normal file
@@ -0,0 +1,42 @@
|
||||
---
|
||||
name: core-guardrails
|
||||
description: Verbindliche Guardrails fuer Architektur-, Refactor-, Zentralisierungs-, Standardisierungs- und Implementierungsaufgaben in diesem Starterkit. Verwenden, wenn Code geaendert, neu strukturiert oder gegen bestehende Layer-/UI-/Security-Standards geprueft werden soll.
|
||||
---
|
||||
|
||||
# Core Guardrails
|
||||
|
||||
## Ziel
|
||||
|
||||
Durchgaengig dieselben technischen Grenzen durchsetzen, damit Core robust, wartbar und vorhersagbar bleibt.
|
||||
|
||||
## Verbindliche Regeln
|
||||
|
||||
1. MUST Layering einhalten (`pages` -> `Service` -> `Repository`, Templates nur Rendering).
|
||||
2. MUST Request/Input/Validation-Contract einhalten (`requestInput()`, `FormErrors`, API-Validation ueber `ApiResponse::validationFromFormErrors(...)`, kein `ApiResponse::readJsonBody(...)` in `pages/api/v1/**`, keine direkten Superglobals in `pages/**`).
|
||||
3. MUST AuthZ/RBAC serverseitig durchsetzen und im UI nur ueber `$viewAuth` steuern.
|
||||
4. MUST Security-Guards einhalten (CSRF auf POST-Endpunkten, keine unredacted PII/Secrets in Logs/Audit-Meta, SQL nur vorbereitet ueber Repository).
|
||||
5. MUST UI-Standards und Data-Contracts fuer Listen/Detailseiten nutzen (Wrapper, Partials, globaler Confirm-Dialog statt `window.confirm`, inklusive globaler Grid-Standards fuer rowInteraction/pageSize).
|
||||
6. MUST Frontend-Hardcuts einhalten (keine inline ESM-Module in Templates/Pages, JS-`src` mit `assetVersion(...)`, zentrale Telemetrie fuer relevante Frontend-Warnings/Fetch-Fehler).
|
||||
7. MUST Quality-Gates ausfuehren und Ergebnis transparent berichten.
|
||||
8. MUST bei Konflikten den regelkonformen Weg waehlen oder den Konflikt als Blocker markieren.
|
||||
9. MUST NOT Extension-Architektur erfinden; dieses Thema ist aktuell Out of Scope.
|
||||
|
||||
## Vorgehen je Aufgabe
|
||||
|
||||
1. Scope bestimmen (`core`, `ui`, `api`, `mixed`).
|
||||
2. Vorhandene Contracts zuerst suchen, dann wiederverwenden.
|
||||
3. Aenderung minimal halten, keine Seiteneffekte ohne Grund.
|
||||
4. Nach Aenderung die relevanten Gates ausfuehren.
|
||||
5. Rest-Risiken explizit benennen.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Extension-Mechanik (Ablageorte, Hooks, Lifecycle) wird hier nicht standardisiert.
|
||||
- Fuer Extensions nur den Status "nicht definiert" dokumentieren, keine impliziten Regeln erfinden.
|
||||
|
||||
## Referenzen
|
||||
|
||||
- Core-Boundaries: `references/boundaries-core.md`
|
||||
- UI-Boundaries: `references/boundaries-ui.md`
|
||||
- Quality-Gates: `references/quality-gates.md`
|
||||
- Source-Map zu Projekt-Doku: `references/source-map.md`
|
||||
45
.agents/skills/core-guardrails/references/boundaries-core.md
Normal file
45
.agents/skills/core-guardrails/references/boundaries-core.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Core Boundaries (MUST / MUST NOT)
|
||||
|
||||
## Schichtgrenzen
|
||||
|
||||
1. MUST SQL nur in `lib/Repository/**` halten.
|
||||
2. MUST Business-Logik in `lib/Service/**` halten.
|
||||
3. MUST `pages/**` auf Input, Auth/AuthZ, Orchestrierung, Response begrenzen.
|
||||
4. MUST NOT Business- oder Permission-Logik in `templates/**` legen.
|
||||
|
||||
## Instanziierung
|
||||
|
||||
1. MUST in Actions/Helpern/Templates nur `app(Foo::class)` verwenden.
|
||||
2. MUST NOT in `pages/**` direkt `new ...Service|Gateway|Repository` nutzen.
|
||||
3. MUST NOT in `lib/Service/**` (ausser `*Factory.php`) direkt `new ...Factory|Service|Gateway|Repository` nutzen.
|
||||
4. MUST NOT in `pages/admin/**` `Factory::class` referenzieren oder `app(...Factory::class)->create...` nutzen.
|
||||
|
||||
## Input / Validation
|
||||
|
||||
1. MUST Input in `pages/**` ueber `requestInput()` lesen.
|
||||
2. MUST NOT `$_POST`, `$_GET`, `$_FILES`, `REQUEST_METHOD` in `pages/**` verwenden.
|
||||
3. MUST NOT `$_SESSION`, `$_SERVER`, `$_COOKIE`, `$_ENV` in `pages/**` direkt verwenden.
|
||||
4. MUST Form-Validation ueber `FormErrors` fuehren.
|
||||
5. MUST API-Validation-Fehler ueber `ApiResponse::validationFromFormErrors(...)` ausgeben.
|
||||
6. MUST NOT `ApiResponse::readJsonBody(...)` in `pages/api/v1/**` verwenden.
|
||||
|
||||
## List-Data Endpoints
|
||||
|
||||
1. MUST `pages/**/data().php` als GET-only Endpunkte umsetzen (`gridRequireGetRequest()`).
|
||||
2. MUST Query-Filter ueber `gridParseFilters(...)` + `filter-schema.php` normalisieren.
|
||||
3. MUST NOT Query-Filter inline/parallele Alias-Parser in `data().php` neu einfuehren.
|
||||
|
||||
## Security / API
|
||||
|
||||
1. MUST AuthZ serverseitig erzwingen.
|
||||
2. MUST Tenant-Scope serverseitig erzwingen.
|
||||
3. MUST CSRF auf POST-Endpunkten vor Body-Verarbeitung verifizieren.
|
||||
4. MUST NOT PII/Secrets unredacted in Logs oder Audit-Metadata schreiben.
|
||||
5. MUST SQL nur ueber Repository mit prepared statements ausfuehren.
|
||||
6. MUST extern UUID-first bleiben.
|
||||
7. MUST API-Fehler konsistent halten (`error`, optional `errors`).
|
||||
8. MUST OpenAPI im selben Merge aktualisieren, wenn API geaendert wird.
|
||||
|
||||
## Pruef-Hinweis
|
||||
|
||||
- Harte Repo-Gates: `tests/Architecture/CoreStarterkitContractTest.php`
|
||||
60
.agents/skills/core-guardrails/references/boundaries-ui.md
Normal file
60
.agents/skills/core-guardrails/references/boundaries-ui.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# UI Boundaries (MUST / MUST NOT)
|
||||
|
||||
## Listen-Standard
|
||||
|
||||
1. MUST Listen ueber `initStandardListPage(...)` initialisieren.
|
||||
2. MUST Filter-Toolbar ueber zentrale Helper/Partials rendern.
|
||||
3. MUST aktive Chips/Drawer-Verhalten ueber Standard-Contracts laufen lassen.
|
||||
4. MUST NOT direkt `gridFiltersFromSchema(...)` oder `initListFilterExperience(...)` in Listen-Templates verwenden.
|
||||
5. MUST NOT Legacy-Filter-Toggle-Markup (`data-toolbar-toggle`, `data-filter-overflow`, `data-filter-toggle`) neu einbauen.
|
||||
6. MUST rowInteraction-Standard fuer Listen mit Row-Navigation beibehalten (sichtbare Action-Spalte + Enter + Doppelklick-Fallback).
|
||||
7. MUST pageSize-Standard beibehalten (10/25/50/100, Toolbar rechts, URL > localStorage > default).
|
||||
|
||||
## Detailseiten-Standard
|
||||
|
||||
1. MUST Hauptformular mit `data-standard-detail-form="1"` markieren.
|
||||
2. MUST Unsaved/Shortcut/Dirty-State ueber `initStandardDetailPage(...)` nutzen.
|
||||
3. MUST Detail-Aktionen ueber Action-Policy-Contract (`data-detail-action-policy`, `data-detail-action-kind`, `data-detail-confirm-message`) steuern.
|
||||
4. MUST NOT inline `confirm(...)` (`onclick` / `onsubmit`) auf standardisierten Detailseiten nutzen.
|
||||
|
||||
## Confirm + Telemetry Standard
|
||||
|
||||
1. MUST Confirm-Dialoge zentral ueber den globalen Confirm-Service abwickeln.
|
||||
2. MUST NOT `window.confirm(...)` in App-JS oder inline HTML-Handlern verwenden.
|
||||
3. MUST relevante Frontend-Warnpfade zentral ueber Frontend-Telemetrie erfassen.
|
||||
4. MUST NOT relevante UX-/Fehlerpfade nur als Console-Warnung implementieren.
|
||||
|
||||
## Frontend Page-Module Hard Cut
|
||||
|
||||
1. MUST Seiteninitialisierung ueber dedizierte Module unter `web/js/pages/*` umsetzen.
|
||||
2. MUST Page-Config ueber `script[type="application/json"]` + `readPageConfig(...)` bereitstellen/lesen.
|
||||
3. MUST alle JS-`src` in `pages/**` und `templates/**` ueber `assetVersion('...js...')` laden.
|
||||
4. MUST NOT inline `<script type="module">...</script>` in `pages/**` oder `templates/**` verwenden.
|
||||
|
||||
## Component Lifecycle Runtime
|
||||
|
||||
1. MUST migrierte Komponenten ueber `init(root, config)` + `destroy()` standardisieren.
|
||||
2. MUST NOT migrierte Komponenten per `DOMContentLoaded`/Module-Sideeffect selbst auto-initialisieren.
|
||||
3. MUST Listener, Timer und Observer, die in `init(...)` entstehen, in `destroy()` wieder abbauen.
|
||||
4. MUST Runtime-Konfiguration ueber Page-Config (`readPageConfig(...)`) beziehen, keine verteilten Ad-hoc-Globals.
|
||||
5. MUST host-gebundene UI-Komponenten ueber explizite `data-app-component`-Hosts im Markup binden.
|
||||
6. Global-Utilities ohne natuerliches Host-Element MAY via Runtime `scope: 'global'` registriert werden, MUESSEN aber denselben Lifecycle-Contract inkl. `destroy()` einhalten.
|
||||
|
||||
## Shared Partials
|
||||
|
||||
1. MUST Listen-Titlebar ueber `templates/partials/app-list-titlebar.phtml` rendern.
|
||||
2. MUST List-Tabs ueber `templates/partials/app-list-tabs.phtml` rendern.
|
||||
3. MUST Purge-Action ueber `templates/partials/app-list-purge-action.phtml` rendern.
|
||||
4. MUST Detail-Validation-Summary ueber `templates/partials/app-details-validation-summary.phtml` rendern.
|
||||
|
||||
## RBAC in Templates
|
||||
|
||||
1. MUST UI-Capabilities nur ueber `$viewAuth` lesen.
|
||||
2. MUST NOT `can('...')` in Templates verwenden.
|
||||
|
||||
## CSS Boundaries
|
||||
|
||||
1. MUST Styles moeglichst lokal in `web/css/components`, `web/css/layout` oder `web/css/pages` halten.
|
||||
2. MUST NOT globale unscoped Overrides ohne klaren Scope einfuehren.
|
||||
3. MUST Vendor-Overrides nur in `web/css/vendor-overrides/**` pflegen.
|
||||
4. MUST bestehende CSS-Variablen bevorzugen statt neue Inline-Farbwerte zu verteilen.
|
||||
40
.agents/skills/core-guardrails/references/quality-gates.md
Normal file
40
.agents/skills/core-guardrails/references/quality-gates.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Quality Gates
|
||||
|
||||
## Pflicht-Gates
|
||||
|
||||
1. `docker compose exec php vendor/bin/phpunit`
|
||||
2. `docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress`
|
||||
3. `docker compose exec php vendor/bin/phpunit tests/Architecture/CoreStarterkitContractTest.php`
|
||||
|
||||
## Struktur-Gates (schnell)
|
||||
|
||||
```bash
|
||||
(rg 'new\s+[^\s(]+Factory\(' lib/Service || true) | wc -l
|
||||
(rg --glob '!**/*Factory.php' 'new\s+[^\s(]+(Service|Gateway|Repository)\(' lib/Service || true) | wc -l
|
||||
(rg "\b(accessServicesFactory|directoryServicesFactory|userServicesFactory|authServicesFactory|tenantServicesFactory|settingServicesFactory|userRepositoryFactory|authRepositoryFactory|authGatewayFactory)\(" pages lib templates web || true) | wc -l
|
||||
(rg -n 'new\s+[^\s(]+(Service|Gateway|Repository)\(' pages -g '*.php' || true) | wc -l
|
||||
(rg -n '\bDB::' pages -g '*.php' || true) | wc -l
|
||||
(rg -n 'app\([^\n]*Factory::class\)->create' pages/admin -g '*.php' || true) | wc -l
|
||||
(rg -n 'Factory::class' pages/admin -g '*.php' || true) | wc -l
|
||||
(rg -n 'ApiResponse::readJsonBody\(' pages/api/v1 -g '*.php' || true) | wc -l
|
||||
```
|
||||
|
||||
Erwartung: jeweils `0`.
|
||||
|
||||
## JS-Scope
|
||||
|
||||
- Bei JS-Aenderungen Browser-Smoke mit DevTools-Console durchfuehren.
|
||||
- Erwartung: keine neuen JS-Errors.
|
||||
|
||||
## Docs-/Skills-Gates (schnell)
|
||||
|
||||
1. `bin/docs-link-check.sh`
|
||||
- prueft Doku-Links in `README.md`, `docs/**`, `.agents/skills/**` und `.agents/**`
|
||||
- `.agents/runs/**` ist standardmaessig ausgeschlossen (historische Artefakte)
|
||||
2. `bin/codex-skills-sync.sh --check`
|
||||
- prueft Drift zwischen Repo-Skills und `~/.codex/skills`
|
||||
|
||||
## Berichtspflicht
|
||||
|
||||
- Bei jedem Gate klar angeben: `passed` / `failed` / `not run`.
|
||||
- Bei `failed` den blocker explizit benennen.
|
||||
25
.agents/skills/core-guardrails/references/source-map.md
Normal file
25
.agents/skills/core-guardrails/references/source-map.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Source Map (Single Source of Truth)
|
||||
|
||||
## Kernregeln
|
||||
|
||||
- Architektur- und Schichtgrenzen: `/docs/explanation-architektur.md`
|
||||
- `lib/**`-Regeln und Instanziierung: `/docs/reference-lib-standards.md`
|
||||
- Kurzkonventionen: `/docs/reference-konventionen.md`
|
||||
- Request/Input/Validation: `/docs/howto-request-input-validation.md`
|
||||
|
||||
## UI-/Frontend-Contracts
|
||||
|
||||
- JavaScript-Standards und Wrapper: `/docs/reference-frontend-javascript.md`
|
||||
- CSS-Standards und Scope-Regeln: `/docs/reference-frontend-css.md`
|
||||
- DoD-Checks: `/docs/reference-entwickler-checkliste.md`
|
||||
- Rollen-Workflow (Planner/Executor/Reviewer/Finalizer): `/.agents/workflow.md`
|
||||
|
||||
## Security / RBAC
|
||||
|
||||
- RBAC-Erweiterungen: `/docs/howto-rbac-permissions-playbook.md`
|
||||
- Sicherheitsmodell: `/docs/explanation-sicherheitsmodell.md`
|
||||
|
||||
## Betrieb und Qualitaetschecks
|
||||
|
||||
- Entwickler-Checkliste: `/docs/reference-entwickler-checkliste.md`
|
||||
- Architektur-Request-Flow: `/docs/tutorial-04-architektur-request-flow.md`
|
||||
38
.agents/skills/starterkit-grid-standards/SKILL.md
Normal file
38
.agents/skills/starterkit-grid-standards/SKILL.md
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
name: starterkit-grid-standards
|
||||
description: Standardisierungs-Skill fuer GridJS-Listen im Starterkit. Verwenden, wenn Listen neu gebaut oder refactored werden sollen (rowInteraction, pageSize, filter drawer, URL-state, accessibility).
|
||||
---
|
||||
|
||||
# Starterkit Grid Standards
|
||||
|
||||
## Ziel
|
||||
|
||||
GridJS-Listen projektweit einheitlich, zuganglich und wartbar halten.
|
||||
|
||||
## Wann verwenden
|
||||
|
||||
1. Neue Listen mit `initStandardListPage(...)` oder `createServerGrid(...)`.
|
||||
2. Refactor von Legacy-Listen.
|
||||
3. Review von UX/Accessibility in Listen.
|
||||
|
||||
## Verbindliche Regeln
|
||||
|
||||
1. MUST `initStandardListPage(...)` als Standard nutzen (nur begruendete Ausnahmen direkt mit `createServerGrid(...)`).
|
||||
2. MUST `rowDblClick.getUrl(...)` fuer zeilenbezogene Navigation setzen, wenn Row-Navigation vorgesehen ist.
|
||||
3. MUST globale `rowInteraction`-Defaults respektieren (Action-Spalte, Enter, Doppelklick-Fallback).
|
||||
4. MUST globale `pageSize`-Standards respektieren (`10/25/50/100`, Toolbar-Placement, URL > storage > default).
|
||||
5. MUST Filter-Drawer/Chips ueber den Standard-Contract nutzen, keine parallelen Custom-Patterns.
|
||||
6. MUST NOT pro Seite eigene Row-Action-Hacks bauen, wenn der Factory-Contract ausreicht.
|
||||
|
||||
## Vorgehen
|
||||
|
||||
1. Ist-Liste gegen `references/list-checklist.md` pruefen.
|
||||
2. Fehlende Standards zuerst zentral in der Factory loesen, danach nur minimale Seitenanpassungen.
|
||||
3. UI/CSS nur als additive Erweiterung zu bestehenden Komponenten.
|
||||
4. Relevante Gates und Browser-Smoke (Keyboard + Console) ausfuehren.
|
||||
|
||||
## Referenzen
|
||||
|
||||
- Checkliste: `references/list-checklist.md`
|
||||
- Row Interaction: `references/row-interaction-standard.md`
|
||||
- Page Size: `references/page-size-standard.md`
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Starterkit Grid Standards"
|
||||
short_description: "Standardize GridJS lists and accessibility patterns"
|
||||
default_prompt: "Use $starterkit-grid-standards to standardize a list page with rowInteraction, pageSize, and filter drawer contracts."
|
||||
@@ -0,0 +1,30 @@
|
||||
# List Checklist
|
||||
|
||||
## Bootstrap
|
||||
|
||||
1. `initStandardListPage({ grid, filters, hooks })` verwendet.
|
||||
2. `filterSchema` aus Server-Config uebergeben.
|
||||
3. `urlSync` bewusst gesetzt.
|
||||
|
||||
## Interaction
|
||||
|
||||
1. `rowDblClick.getUrl(...)` liefert stabile Ziel-URL oder leer.
|
||||
2. Keine Doppel-Action-Spalte (Factory auto-action vs explizite actions).
|
||||
3. Enter/Pointer/Focus fuer oeffnbare Rows funktionieren.
|
||||
|
||||
## Pagination + URL
|
||||
|
||||
1. Page-size Optionen nur `10/25/50/100`.
|
||||
2. URL Sync pruefen (`page`, `order`, `dir`, `limit`).
|
||||
3. Default-Werte erzeugen saubere URL.
|
||||
|
||||
## Filter UX
|
||||
|
||||
1. Search sichtbar.
|
||||
2. Drawer-Filter und Chips intakt.
|
||||
3. Reset/Apply Verhalten reproduzierbar.
|
||||
|
||||
## Regression
|
||||
|
||||
1. Sortierung, Selection/Bulk, Doppelklick unveraendert.
|
||||
2. Keine neuen Console Errors.
|
||||
@@ -0,0 +1,20 @@
|
||||
# Page Size Standard
|
||||
|
||||
## Globale Defaults
|
||||
|
||||
1. Optionen: `10`, `25`, `50`, `100`.
|
||||
2. Default: `10`.
|
||||
3. Prioritaet: `URL > localStorage > Default`.
|
||||
4. Placement: obere `app-list-toolbar`, rechts ausgerichtet.
|
||||
|
||||
## URL Contract
|
||||
|
||||
1. Param: `limit`.
|
||||
2. Bei Default-Limit optional clean URL (Param entfernen).
|
||||
3. Bei Hard-Reload muss gesetztes URL-Limit reproduzierbar sein.
|
||||
|
||||
## Verhalten
|
||||
|
||||
1. Aenderung der Seitengroesse setzt Seite auf 1.
|
||||
2. Sortierung/Filter bleiben erhalten.
|
||||
3. LocalStorage-Key pro Tabelle (path + dataUrl + container).
|
||||
@@ -0,0 +1,31 @@
|
||||
# Row Interaction Standard
|
||||
|
||||
## Ziel
|
||||
|
||||
Row-Navigation discoverable und keyboard-freundlich machen.
|
||||
|
||||
## Standardverhalten
|
||||
|
||||
1. Sichtbare Action-Spalte rechts (`Open`/`Edit`) fuer Listen mit `rowDblClick`.
|
||||
2. Enter auf fokussierter Row loest dieselbe Navigation aus.
|
||||
3. Doppelklick bleibt als Fallback fuer Power-User.
|
||||
4. Nur Rows mit Ziel-URL erhalten `data-row-open-url`.
|
||||
|
||||
## Contract
|
||||
|
||||
```js
|
||||
rowInteraction: {
|
||||
enabled: true,
|
||||
showActionButton: true,
|
||||
keepDblClick: true,
|
||||
enableEnterOnRow: true,
|
||||
actionColumnLabel: 'Actions',
|
||||
resolveActionLabel: (url, rowData) => (url.includes('/edit/') ? 'Edit' : 'Open')
|
||||
}
|
||||
```
|
||||
|
||||
## Guardrails
|
||||
|
||||
1. Keine globale Tab-Stop-Flut auf allen Rows.
|
||||
2. Fokusstil fuer Row und Action-Button sichtbar.
|
||||
3. Explizite `actions.enabled: true` pro Seite darf Auto-Action uebersteuern.
|
||||
37
.agents/skills/starterkit-php-style-ci/SKILL.md
Normal file
37
.agents/skills/starterkit-php-style-ci/SKILL.md
Normal file
@@ -0,0 +1,37 @@
|
||||
---
|
||||
name: starterkit-php-style-ci
|
||||
description: Standard-Skill fuer PHP Coding-Style im Starterkit (php-cs-fixer, dry-run in CI, lokaler fix/check workflow). Verwenden bei Style-Einfuehrung, CI-Checks oder grossen Format-Diffs.
|
||||
---
|
||||
|
||||
# Starterkit PHP Style CI
|
||||
|
||||
## Ziel
|
||||
|
||||
Coding-Style pruefbar, reproduzierbar und regressionsarm machen.
|
||||
|
||||
## Wann verwenden
|
||||
|
||||
1. Einfuehrung oder Nachschaerfung von Style-Regeln.
|
||||
2. CI-Dry-Run fuer Style-Checks.
|
||||
3. Aufraeumen grosser Style-Diff-Wellen.
|
||||
|
||||
## Verbindliche Regeln
|
||||
|
||||
1. MUST `composer cs:check` fuer nicht-mutierende Pruefung nutzen.
|
||||
2. MUST `composer cs:fix` nur bewusst und mit Diff-Kontrolle ausfuehren.
|
||||
3. MUST Style-Check vor Merge gruen halten (lokal und optional CI).
|
||||
4. MUST nach groesseren Fixes mindestens `phpunit` und `phpstan` laufen lassen.
|
||||
5. MUST NOT manuell Einzelstellen formatieren, wenn der Fixer sie zentral loesen kann.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Baseline erfassen: `composer cs:check`.
|
||||
2. Falls noetig fixen: `composer cs:fix`.
|
||||
3. Diff fokussiert pruefen (Imports, Braces, Nebenwirkungen).
|
||||
4. Qualitaetsgates laufen lassen.
|
||||
5. CI-Dry-Run konfigurieren oder validieren.
|
||||
|
||||
## Referenzen
|
||||
|
||||
- Lokaler Workflow: `references/style-workflow.md`
|
||||
- CI Dry Run: `references/ci-dry-run.md`
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Starterkit PHP Style CI"
|
||||
short_description: "Enforce PHP coding style with safe local and CI checks"
|
||||
default_prompt: "Use $starterkit-php-style-ci to set up and run php-cs-fixer check/fix workflow with CI dry-run and guardrails."
|
||||
@@ -0,0 +1,21 @@
|
||||
# CI Dry Run
|
||||
|
||||
## Ziel
|
||||
|
||||
CI soll nur pruefen, nicht formatieren.
|
||||
|
||||
## Minimaler Check
|
||||
|
||||
```bash
|
||||
composer cs:check
|
||||
```
|
||||
|
||||
## Erwartung
|
||||
|
||||
1. Exit Code 0: Style konform.
|
||||
2. Exit Code != 0: Diff ausgeben, Entwickler fuehrt lokal `composer cs:fix` aus.
|
||||
|
||||
## Hinweise
|
||||
|
||||
1. Kein Auto-Commit aus CI.
|
||||
2. Bei initialen Altlasten zuerst einmalige Bereinigung auf dediziertem Branch.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Local Style Workflow
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
composer cs:check
|
||||
composer cs:fix
|
||||
```
|
||||
|
||||
## Praktikabler Ablauf
|
||||
|
||||
1. Erst `cs:check` laufen lassen.
|
||||
2. Danach `cs:fix`.
|
||||
3. Nur relevante Diffs uebernehmen, grosse Misch-Diffs vermeiden.
|
||||
4. Anschliessend:
|
||||
|
||||
```bash
|
||||
docker compose exec php vendor/bin/phpunit
|
||||
docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress
|
||||
```
|
||||
|
||||
## Review-Fokus
|
||||
|
||||
1. `ordered_imports`, `braces_position`, `statement_indentation`.
|
||||
2. Kein semantischer Drift bei anon classes, arrow functions, array maps.
|
||||
58
.agents/skills/starterkit-planner/SKILL.md
Normal file
58
.agents/skills/starterkit-planner/SKILL.md
Normal file
@@ -0,0 +1,58 @@
|
||||
---
|
||||
name: starterkit-planner
|
||||
description: Planungs-Skill fuer Architektur-, Rollout-, Refactor- und Standardisierungsaufgaben im Starterkit. Verwenden, wenn ein decision-complete Plan mit klaren Interfaces, Tests, Risiken und Annahmen benoetigt wird.
|
||||
---
|
||||
|
||||
# Starterkit Planner
|
||||
|
||||
## Ziel
|
||||
|
||||
Planungen so strukturieren, dass Implementierung ohne offene Entscheidungen moeglich ist.
|
||||
Bei Agent-Workflows muss der Plan maschinenlesbar in die Projekt-Contracts passen.
|
||||
|
||||
## Verbindliches Ausgabeformat
|
||||
|
||||
1. Ziel + Success Criteria
|
||||
2. In/Out-of-Scope
|
||||
3. Entscheidungsmatrix (Optionen + Gruende)
|
||||
4. Decision-complete Implementierungsplan
|
||||
5. Tests/Abnahme
|
||||
6. Risiken/Migrationshinweise
|
||||
7. Annahmen/Defaults
|
||||
|
||||
Wenn `.agents/` verwendet wird:
|
||||
|
||||
1. Plan muss dem Schema `.agents/contracts/planner.schema.json` entsprechen.
|
||||
2. Success Criteria muessen stabile IDs tragen (`SC-001`, `SC-002`, ...).
|
||||
3. Success Criteria muessen so formuliert sein, dass Reviewer Acceptance sie direkt gegen `criterion_id` pruefen kann.
|
||||
4. Guard- und Quality-Gate-IDs muessen aus den Katalogen kommen (`GR-*`, `QG-*`).
|
||||
|
||||
## Vorgehen
|
||||
|
||||
1. Ist-Zustand kurz aus Repo-Fakten ableiten.
|
||||
2. Entscheidungen mit Tradeoffs transparent machen.
|
||||
3. Oeffentliche Contracts explizit benennen.
|
||||
4. Success Criteria frueh mit stabilen IDs (`SC-*`) definieren.
|
||||
5. Reihenfolge und Rollout so planen, dass Rueckbau moeglich bleibt.
|
||||
6. Teststrategie nach Risiko priorisieren.
|
||||
|
||||
## Qualitaetskriterien
|
||||
|
||||
1. Keine vagen TODO-Entscheidungen im Plan.
|
||||
2. Jeder betroffene Bereich hat klare Akzeptanzkriterien mit stabiler ID (`SC-*`).
|
||||
3. Risiken sind priorisiert und beobachtbar.
|
||||
4. Ungeklaerte Themen stehen explizit unter Annahmen.
|
||||
5. Guard-/Gate-Referenzen sind vollstaendig und pruefbar (`GR-*`, `QG-*`).
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Extension-Mechanik ist aktuell nicht standardisiert.
|
||||
- Keine impliziten Extension-Regeln definieren.
|
||||
|
||||
## Referenzen
|
||||
|
||||
- Plan-Grundgeruest: `references/plan-template.md`
|
||||
- Entscheidungsraster: `references/tradeoff-matrix.md`
|
||||
- Agent Planner Contract: `.agents/contracts/planner.schema.json`
|
||||
- Guard Catalog: `.agents/checks/guard-catalog.json`
|
||||
- Quality Gates: `.agents/checks/quality-gates.json`
|
||||
@@ -0,0 +1,50 @@
|
||||
# Plan Template (Decision Complete)
|
||||
|
||||
## 1) Ziel + Success Criteria
|
||||
|
||||
- Was wird verbessert?
|
||||
- Woran ist messbar, dass es erfolgreich ist?
|
||||
- Success Criteria immer mit stabilen IDs formulieren (`SC-001`, `SC-002`, ...).
|
||||
|
||||
Beispiel:
|
||||
|
||||
- `SC-001`: Delete-Aktion zeigt Confirm-Dialog mit korrekter Gefahr-Variante.
|
||||
- `SC-002`: Nach Confirm erfolgt genau ein Submit (kein Doppel-Submit).
|
||||
|
||||
## 2) Scope
|
||||
|
||||
- In Scope
|
||||
- Out of Scope
|
||||
- Scope-Typ explizit markieren (`core`, `ui`, `api`, `mixed`), wenn der Workflow es verlangt.
|
||||
|
||||
## 3) Oeffentliche Interfaces / Contracts
|
||||
|
||||
- Neue/angepasste APIs, Data-Contracts, CLI-Flags, Markup-Contracts
|
||||
- Backward-Compatibility-Entscheidung
|
||||
- Bei Agent-Workflow: verwendete `GR-*` und `QG-*` IDs explizit nennen.
|
||||
|
||||
## 4) Implementierungsschritte
|
||||
|
||||
1. Schritt A
|
||||
2. Schritt B
|
||||
3. Schritt C
|
||||
|
||||
Regel: Jeder Schritt ist direkt umsetzbar ohne Nachentscheid.
|
||||
|
||||
## 5) Test- und Abnahmeplan
|
||||
|
||||
- Syntax/Static Checks
|
||||
- Contract-/Architekturtests
|
||||
- Fachliche Smoke-Tests
|
||||
- Abnahmekriterien (klar messbar)
|
||||
- Abnahme-Checks 1:1 auf `SC-*` Kriterien-ID referenzieren.
|
||||
|
||||
## 6) Risiken / Migration
|
||||
|
||||
- Hauptrisiken
|
||||
- Mitigation
|
||||
- Rollout-/Rollback-Hinweis
|
||||
|
||||
## 7) Annahmen / Defaults
|
||||
|
||||
- Alle offenen Themen als explizite Annahme festhalten.
|
||||
@@ -0,0 +1,34 @@
|
||||
# Tradeoff Matrix
|
||||
|
||||
## Bewertungsachsen
|
||||
|
||||
1. Robustheit / Fehlertoleranz
|
||||
2. Wartbarkeit / Kopplung
|
||||
3. Migrationsrisiko
|
||||
4. Testbarkeit
|
||||
5. Liefergeschwindigkeit
|
||||
|
||||
## Standard-Optionen
|
||||
|
||||
### Option A: Zentralisieren im Core
|
||||
|
||||
- Vorteile: Konsistenz, weniger Duplikate
|
||||
- Nachteile: Hoher Impact, breiter Testbedarf
|
||||
- Geeignet wenn: 3+ Stellen betroffen oder Contract-Sicherheit steigt deutlich
|
||||
|
||||
### Option B: Shared Partial/Helper
|
||||
|
||||
- Vorteile: Schneller Nutzen, moderates Risiko
|
||||
- Nachteile: Teilweise Restduplikate moeglich
|
||||
- Geeignet wenn: Wiederkehrendes UI-/Glue-Muster mit klaren Datencontracts
|
||||
|
||||
### Option C: Lokal belassen
|
||||
|
||||
- Vorteile: Geringstes kurzfristiges Risiko
|
||||
- Nachteile: Langfristig mehr Wartung, inkonsistente UX
|
||||
- Geeignet wenn: Einzelfall oder experimentelle Logik
|
||||
|
||||
## Entscheidungsregel
|
||||
|
||||
- Standardempfehlung: Option B vor Option A, wenn Nutzen hoch und Migrationsradius kleiner ist.
|
||||
- Option C nur mit expliziter Begruendung (z. B. bewusstes Out-of-Scope oder Legacy-Risiko).
|
||||
32
.agents/templates/analysis.template.json
Normal file
32
.agents/templates/analysis.template.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"task_id": "TASK-0001",
|
||||
"issue_summary": "Short summary of the issue or feature request",
|
||||
"affected_layers": ["Service", "pages"],
|
||||
"affected_files": [
|
||||
{
|
||||
"path": "path/to/file.php",
|
||||
"role": "Service that handles X"
|
||||
}
|
||||
],
|
||||
"existing_patterns": [
|
||||
"Uses app-details-titlebar partial",
|
||||
"Follows PRG pattern in similar actions"
|
||||
],
|
||||
"related_tests": [
|
||||
"tests/Service/XServiceTest.php"
|
||||
],
|
||||
"security_surface": {
|
||||
"authz_relevant": false,
|
||||
"tenant_scope_relevant": false,
|
||||
"input_handling": true,
|
||||
"crypto_relevant": false,
|
||||
"file_upload_relevant": false,
|
||||
"notes": ""
|
||||
},
|
||||
"assumptions": [
|
||||
"Assumption the Planner must resolve"
|
||||
],
|
||||
"risks_discovered": [
|
||||
"Risk discovered during analysis"
|
||||
]
|
||||
}
|
||||
39
.agents/templates/execution-report.template.json
Normal file
39
.agents/templates/execution-report.template.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"task_id": "TASK-0001",
|
||||
"plan_ref": ".agents/runs/TASK-0001/plan.json",
|
||||
"status": "done",
|
||||
"changed_files": [
|
||||
{
|
||||
"path": "path/to/file",
|
||||
"summary": "What changed"
|
||||
}
|
||||
],
|
||||
"guard_evidence": [
|
||||
{
|
||||
"guard_id": "GR-CORE-003",
|
||||
"status": "pass",
|
||||
"evidence": "Short evidence with file or test reference."
|
||||
}
|
||||
],
|
||||
"commands": [
|
||||
{
|
||||
"cmd": "docker compose exec php vendor/bin/phpunit",
|
||||
"result": "pass"
|
||||
}
|
||||
],
|
||||
"quality_gate_results": [
|
||||
{
|
||||
"gate_id": "QG-001",
|
||||
"result": "pass",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"test_results": [
|
||||
{
|
||||
"name": "test name",
|
||||
"result": "pass",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"open_items": []
|
||||
}
|
||||
12
.agents/templates/finalize.template.json
Normal file
12
.agents/templates/finalize.template.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"task_id": "TASK-0001",
|
||||
"ready_to_finalize": false,
|
||||
"code_review": "pass",
|
||||
"security_review": "pass",
|
||||
"acceptance_review": "pass",
|
||||
"ci_status": "unknown",
|
||||
"final_action": "hold",
|
||||
"hold_reason": "Waiting for all three reviews and quality gates to pass.",
|
||||
"commit_message": "",
|
||||
"notes": ""
|
||||
}
|
||||
50
.agents/templates/plan.template.json
Normal file
50
.agents/templates/plan.template.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"task_id": "TASK-0001",
|
||||
"analysis_ref": ".agents/runs/TASK-0001/analysis.json",
|
||||
"summary": "Short summary of issue or feature",
|
||||
"assumptions": [],
|
||||
"scope": {
|
||||
"in": [],
|
||||
"out": []
|
||||
},
|
||||
"guardrails": {
|
||||
"required_guard_ids": [
|
||||
"GR-CORE-003",
|
||||
"GR-TEST-001",
|
||||
"GR-SEC-008"
|
||||
],
|
||||
"required_quality_gate_ids": [
|
||||
"QG-001",
|
||||
"QG-002",
|
||||
"QG-003"
|
||||
]
|
||||
},
|
||||
"success_criteria": [
|
||||
{
|
||||
"id": "SC-001",
|
||||
"criterion": "Measurable acceptance criterion."
|
||||
}
|
||||
],
|
||||
"implementation_steps": [
|
||||
{
|
||||
"id": "S1",
|
||||
"title": "Step title",
|
||||
"description": "Step detail",
|
||||
"guard_refs": [
|
||||
"GR-CORE-003"
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
"Test name or PHPUnit class that proves the feature works"
|
||||
],
|
||||
"acceptance_checks": [
|
||||
"SC-001: Verifiable acceptance step for criterion SC-001"
|
||||
],
|
||||
"risks": [
|
||||
{
|
||||
"risk": "Risk description",
|
||||
"mitigation": "Mitigation description"
|
||||
}
|
||||
]
|
||||
}
|
||||
16
.agents/templates/review-acceptance.template.json
Normal file
16
.agents/templates/review-acceptance.template.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"task_id": "TASK-0001",
|
||||
"verdict": "pass",
|
||||
"checked_criterion_ids": [
|
||||
"SC-001"
|
||||
],
|
||||
"checks": [
|
||||
{
|
||||
"criterion_id": "SC-001",
|
||||
"criterion": "criterion text",
|
||||
"result": "pass",
|
||||
"evidence": "Reference to proof (test, file, manual smoke step)."
|
||||
}
|
||||
],
|
||||
"missing_or_wrong": []
|
||||
}
|
||||
14
.agents/templates/review-code.template.json
Normal file
14
.agents/templates/review-code.template.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"task_id": "TASK-0001",
|
||||
"verdict": "pass",
|
||||
"checked_guard_ids": [
|
||||
"GR-CORE-003",
|
||||
"GR-TEST-001"
|
||||
],
|
||||
"checked_quality_gate_ids": [
|
||||
"QG-001",
|
||||
"QG-002",
|
||||
"QG-003"
|
||||
],
|
||||
"findings": []
|
||||
}
|
||||
9
.agents/templates/review-security.template.json
Normal file
9
.agents/templates/review-security.template.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"task_id": "TASK-0001",
|
||||
"verdict": "pass",
|
||||
"checked_guard_ids": [
|
||||
"GR-SEC-008",
|
||||
"GR-SEC-009"
|
||||
],
|
||||
"findings": []
|
||||
}
|
||||
125
.agents/workflow.md
Normal file
125
.agents/workflow.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Agent Workflow
|
||||
|
||||
Last updated: 2026-03-19
|
||||
|
||||
## Overview
|
||||
|
||||
This project uses a 7-role workflow for issue and feature delivery.
|
||||
|
||||
```
|
||||
Analyst → Planner → Executor → Code Reviewer ──┐
|
||||
├→ Finalizer
|
||||
Security Reviewer ──────┤
|
||||
Acceptance Tester ───────┘
|
||||
```
|
||||
|
||||
Primary goals:
|
||||
- Front-load context gathering (Analyst) so downstream roles start informed
|
||||
- Separate code quality review from security review for focused attention
|
||||
- Explicit guard IDs (`GR-*`), gate IDs (`QG-*`), and success criteria (`SC-*`) across all roles
|
||||
- Fast retry loop from reviewers back to executor
|
||||
|
||||
Source of truth:
|
||||
- Guard catalog (22 guards): `.agents/checks/guard-catalog.json`
|
||||
- Quality gates (9 gates): `.agents/checks/quality-gates.json`
|
||||
- Contracts: `.agents/contracts/`
|
||||
|
||||
---
|
||||
|
||||
## Roles
|
||||
|
||||
### Analyst
|
||||
- **Input:** issue description or feature request
|
||||
- **Output:** `analysis.json` (see `.agents/contracts/analyst.schema.json`)
|
||||
- Gathers context: affected layers, files, patterns, tests, security surface
|
||||
- Does NOT propose solutions — only structures facts for the Planner
|
||||
|
||||
### Planner
|
||||
- **Input:** `analysis.json`
|
||||
- **Output:** `plan.json` (see `.agents/contracts/planner.schema.json`)
|
||||
- Defines scope, guard selection, success criteria, implementation steps, risks
|
||||
- References concrete file paths from analysis — does not re-explore codebase
|
||||
|
||||
### Executor
|
||||
- **Input:** approved `plan.json`
|
||||
- **Output:** `execution-report.json` (see `.agents/contracts/executor.schema.json`)
|
||||
- Implements plan, runs quality gates, provides guard evidence
|
||||
|
||||
### Code Reviewer
|
||||
- **Input:** code diff + `execution-report.json`
|
||||
- **Output:** `review-code.json` (see `.agents/contracts/reviewer-code.schema.json`)
|
||||
- Scope: architecture, conventions, testing, UI standards (13 guards)
|
||||
- Guards: `GR-CORE-*`, `GR-TEST-*`, `GR-UI-*`
|
||||
|
||||
### Security Reviewer
|
||||
- **Input:** code diff + `execution-report.json`
|
||||
- **Output:** `review-security.json` (see `.agents/contracts/reviewer-security.schema.json`)
|
||||
- Scope: authz, tenant scope, CSRF, input validation, crypto, file storage (9 guards)
|
||||
- Guards: `GR-SEC-*`
|
||||
- Any `critical` or `high` finding forces `fail` verdict
|
||||
|
||||
### Acceptance Tester
|
||||
- **Input:** code diff + `plan.json`
|
||||
- **Output:** `review-acceptance.json` (see `.agents/contracts/reviewer-acceptance.schema.json`)
|
||||
- Verifies each `SC-*` success criterion is met
|
||||
|
||||
### Finalizer
|
||||
- **Input:** `review-code.json` + `review-security.json` + `review-acceptance.json`
|
||||
- **Output:** `finalize.json` (see `.agents/contracts/finalizer.schema.json`)
|
||||
- All three reviews must pass. CI must be green. Otherwise: hold.
|
||||
|
||||
---
|
||||
|
||||
## State Machine
|
||||
|
||||
```
|
||||
analyzed → planned → executing → reviewing → finalize → done
|
||||
↑ |
|
||||
└────────────┘ (on any FAIL)
|
||||
```
|
||||
|
||||
The reviewing state runs Code Reviewer, Security Reviewer, and Acceptance Tester.
|
||||
If any reviewer returns `FAIL`, state goes back to `executing` with explicit findings.
|
||||
|
||||
## Handover Artifacts
|
||||
|
||||
| Role | Artifact |
|
||||
|---|---|
|
||||
| Analyst | `analysis.json` |
|
||||
| Planner | `plan.json` |
|
||||
| Executor | `execution-report.json` |
|
||||
| Code Reviewer | `review-code.json` |
|
||||
| Security Reviewer | `review-security.json` |
|
||||
| Acceptance Tester | `review-acceptance.json` |
|
||||
| Finalizer | `finalize.json` |
|
||||
|
||||
## Fail Loop Rule
|
||||
|
||||
No free-text "please improve". Every fail must include:
|
||||
- `id`
|
||||
- `severity`
|
||||
- `file`
|
||||
- expected fix
|
||||
|
||||
## Guard Assignment
|
||||
|
||||
Guards are split by reviewer role (see `reviewer` field in guard-catalog.json):
|
||||
|
||||
**Code Reviewer** (13 guards): GR-CORE-003, GR-CORE-007, GR-CORE-010, GR-CORE-011, GR-CORE-012, GR-TEST-001, GR-TEST-002, GR-UI-014, GR-UI-LIST, GR-UI-DETAIL, GR-UI-A11Y, GR-UI-I18N, GR-UI-REUSE
|
||||
|
||||
**Security Reviewer** (9 guards): GR-SEC-001 through GR-SEC-009
|
||||
|
||||
## What automated tests already enforce
|
||||
|
||||
The following concerns are covered by QG-001/QG-003/QG-004 and do NOT need manual guard review:
|
||||
- Layering boundaries (CoreStarterkitContractTest)
|
||||
- No direct service instantiation in pages (structural rg checks)
|
||||
- No superglobals in pages (architecture tests)
|
||||
- PSR-4 namespace alignment (autoloader + QG-003)
|
||||
- PHP code style (QG-006)
|
||||
- Module namespace isolation (ModuleStructureContractTest)
|
||||
- Module UI via slots only (NoBookmarksHardcodingTest, NoAddressBookHardcodingTest)
|
||||
- Runtime fingerprint (web/index.php fail-fast)
|
||||
- Repository sanitizeLimitOffset (RepositoryInterfaceContractTest)
|
||||
- List init standard, legacy filter toggle, template RBAC (architecture tests)
|
||||
- Component lifecycle contract (architecture tests)
|
||||
Reference in New Issue
Block a user