Files
breadcrumb-the-shire/agent-system/runs/TEST-COVERAGE-SERVICES-001/plan.json
2026-03-13 12:05:34 +01:00

150 lines
6.3 KiB
JSON

{
"task_id": "TEST-COVERAGE-SERVICES-001",
"summary": "Add PHPUnit tests for 7 critical untested services: PermissionService, RoleService, DepartmentService, TenantService, MailService, UserLifecycleService, RateLimiterService.",
"assumptions": [
"All 7 services use constructor injection and are unit-testable with mocks (GR-TEST-002 compliant).",
"Focus on happy path + at least one failure/edge case per public method (GR-TEST-001).",
"Services that orchestrate repositories will have repositories mocked.",
"MailService test will mock PHPMailer — no actual email sending."
],
"scope": {
"in": [
"New: tests/Service/Access/PermissionServiceTest.php — CRUD + permission assignment logic",
"New: tests/Service/Access/RoleServiceTest.php — CRUD + role validation",
"New: tests/Service/Org/DepartmentServiceTest.php — CRUD + hierarchy validation",
"New: tests/Service/Tenant/TenantServiceTest.php — CRUD + tenant lifecycle",
"New: tests/Service/Mail/MailServiceTest.php — composition + send + error handling",
"New: tests/Service/User/UserLifecycleServiceTest.php — state transitions (active/inactive/deleted)",
"New: tests/Service/Security/RateLimiterServiceTest.php — rate limit enforcement + reset"
],
"out": [
"Repository tests (separate task)",
"Gateway tests (separate task)",
"Integration/E2E tests",
"Production code changes (test-only task)",
"Medium/low priority untested services (BrandingService, SearchDataService, etc.)"
]
},
"guardrails": {
"required_guard_ids": [
"GR-TEST-001",
"GR-TEST-002",
"GR-LANG-001",
"GR-LANG-002"
],
"required_quality_gate_ids": [
"QG-001",
"QG-002",
"QG-006"
]
},
"success_criteria": [
{
"id": "SC-001",
"criterion": "All 7 test files exist and contain at least one happy-path and one failure/edge-case test per public method of the corresponding service."
},
{
"id": "SC-002",
"criterion": "Each test file uses proper mocking (createMock) for all injected dependencies — no real DB or HTTP calls."
},
{
"id": "SC-003",
"criterion": "Total new test methods >= 40 across the 7 files (average ~6 per service)."
},
{
"id": "SC-004",
"criterion": "PHPUnit full suite (QG-001) passes green including all new tests."
},
{
"id": "SC-005",
"criterion": "PHPStan (QG-002) passes green — test files are type-safe."
}
],
"implementation_steps": [
{
"id": "S1",
"title": "Analyze public API of all 7 services",
"description": "Read each service file, list all public methods, identify constructor dependencies, and plan test scenarios (happy path + edge cases).",
"guard_refs": ["GR-TEST-001"]
},
{
"id": "S2",
"title": "Write PermissionServiceTest",
"description": "Test CRUD operations (createFromAdmin, updateFromAdmin, deleteById), permission assignment, and validation error paths.",
"guard_refs": ["GR-TEST-001", "GR-TEST-002"]
},
{
"id": "S3",
"title": "Write RoleServiceTest",
"description": "Test CRUD operations, role validation (duplicate name, missing fields), and permission assignment.",
"guard_refs": ["GR-TEST-001", "GR-TEST-002"]
},
{
"id": "S4",
"title": "Write DepartmentServiceTest",
"description": "Test CRUD operations, hierarchy validation, tenant scope enforcement.",
"guard_refs": ["GR-TEST-001", "GR-TEST-002"]
},
{
"id": "S5",
"title": "Write TenantServiceTest",
"description": "Test CRUD operations, tenant lifecycle (activate/deactivate), slug generation, validation.",
"guard_refs": ["GR-TEST-001", "GR-TEST-002"]
},
{
"id": "S6",
"title": "Write MailServiceTest",
"description": "Test email composition, recipient validation, template rendering, and error handling when SMTP fails. Mock PHPMailer.",
"guard_refs": ["GR-TEST-001", "GR-TEST-002"]
},
{
"id": "S7",
"title": "Write UserLifecycleServiceTest",
"description": "Test state transitions: active->inactive, inactive->active, soft-delete, restore. Test audit trail calls.",
"guard_refs": ["GR-TEST-001", "GR-TEST-002"]
},
{
"id": "S8",
"title": "Write RateLimiterServiceTest",
"description": "Test rate limit enforcement (under limit, at limit, over limit), reset, and TTL expiration.",
"guard_refs": ["GR-TEST-001", "GR-TEST-002"]
},
{
"id": "S9",
"title": "Run quality gates",
"description": "QG-001 PHPUnit full, QG-002 PHPStan, QG-006 CS check.",
"guard_refs": ["GR-LANG-002"]
}
],
"tests": [
"tests/Service/Access/PermissionServiceTest.php",
"tests/Service/Access/RoleServiceTest.php",
"tests/Service/Org/DepartmentServiceTest.php",
"tests/Service/Tenant/TenantServiceTest.php",
"tests/Service/Mail/MailServiceTest.php",
"tests/Service/User/UserLifecycleServiceTest.php",
"tests/Service/Security/RateLimiterServiceTest.php"
],
"acceptance_checks": [
"SC-001: Each test file covers every public method of its service with happy + failure paths",
"SC-002: rg 'createMock' in all 7 test files shows proper dependency mocking",
"SC-003: phpunit --list-tests | grep -c 'Test::test' for new files totals >= 40",
"SC-004: docker compose exec php vendor/bin/phpunit exits 0",
"SC-005: docker compose exec php vendor/bin/phpstan analyse exits 0"
],
"risks": [
{
"risk": "Services with complex dependencies (MailService depends on PHPMailer, SMTP config) may be hard to mock",
"mitigation": "Use interface-based mocking. If PHPMailer is used directly, mock at the gateway boundary instead."
},
{
"risk": "UserLifecycleService may have implicit state dependencies (session, tenant context)",
"mitigation": "Analyze constructor carefully. Mock all injected gateways/services. If static state access exists, document as tech debt for later refactor."
},
{
"risk": "Scope creep — discovering untestable code that needs refactoring",
"mitigation": "Document untestable patterns as findings but do NOT refactor production code in this task. Create follow-up tasks instead."
}
]
}