{ "task_id": "CODE-DEDUP-ACTIONS-001", "plan_ref": "agent-system/runs/CODE-DEDUP-ACTIONS-001/plan.json", "status": "done", "changed_files": [ { "path": "lib/Service/Audit/AuditMetadataEnricher.php", "summary": "CREATED — S1: New service resolving audit user IDs (created_by, modified_by, etc.) into display labels and UUIDs. Accepts configurable field list. Depends on UserReadRepositoryInterface." }, { "path": "lib/Service/Data/GridUserCountEnricher.php", "summary": "CREATED — S2: New stateless service that collects entity IDs from grid rows, batch-queries total and active user counts via callables, and returns a lookup map." }, { "path": "tests/Service/Audit/AuditMetadataEnricherTest.php", "summary": "CREATED — S3: 6 tests covering label resolution, email fallback, zero/missing IDs, user not found, and custom fields." }, { "path": "tests/Service/Data/GridUserCountEnricherTest.php", "summary": "CREATED — S3: 6 tests covering typical rows, empty rows, ID deduplication, zero IDs, zero counts, and negative inactive clamping." }, { "path": "lib/App/Container/Registrars/AppServicesRegistrar.php", "summary": "S4: Registered AuditMetadataEnricher (with UserReadRepository dep) and GridUserCountEnricher (stateless) in DI container." }, { "path": "pages/admin/tenants/edit($id).php", "summary": "S5: Replaced 27 lines of inline audit metadata resolution (created_by, modified_by, status_changed_by) with single AuditMetadataEnricher call. Removed unused $userAccountService variable." }, { "path": "pages/admin/roles/edit($id).php", "summary": "S5: Replaced 18 lines of inline audit metadata resolution (created_by, modified_by) with single AuditMetadataEnricher call. Removed unused $userAccountService variable." }, { "path": "pages/admin/departments/edit($id).php", "summary": "S5: Replaced 18 lines of inline audit metadata resolution (created_by, modified_by) with single AuditMetadataEnricher call. Removed unused $userAccountService variable." }, { "path": "pages/admin/users/edit($id).php", "summary": "S5: Replaced 28 lines of inline audit metadata resolution (created_by, modified_by, active_changed_by) with single AuditMetadataEnricher call inside permission guard." }, { "path": "pages/admin/roles/data().php", "summary": "S6: Replaced 12 lines of ID collection + user count aggregation with GridUserCountEnricher.computeCounts() call. Row loop uses count map lookup." }, { "path": "pages/admin/departments/data().php", "summary": "S6: Replaced 11 lines of ID collection + user count aggregation with GridUserCountEnricher.computeCounts() call. Row loop uses count map lookup." }, { "path": "pages/admin/tenants/data().php", "summary": "S6: Replaced 8 lines of ID collection + user count aggregation inside $fetchRows closure with GridUserCountEnricher.computeCounts() call. Also uses enricher IDs for SSO map query." } ], "guard_evidence": [ { "guard_id": "GR-CORE-001", "status": "pass", "evidence": "AuditMetadataEnricher is a Service class with single repository dependency (UserReadRepositoryInterface). GridUserCountEnricher is a stateless Service with no dependencies. Both follow the Service contract — business logic, no HTML, no orchestration flow." }, { "guard_id": "GR-CORE-002", "status": "pass", "evidence": "Strict layering preserved. New services registered in AppServicesRegistrar. Action files call services via app() helper. No cross-layer violations. No circular dependencies." }, { "guard_id": "GR-TEST-001", "status": "pass", "evidence": "12 new tests added (6 per service). 603 total tests run, 0 errors introduced by this task. 1 pre-existing failure (TranslationKeysTest) unrelated." }, { "guard_id": "GR-TEST-002", "status": "pass", "evidence": "New tests cover edge cases: zero IDs, missing fields, user not found, email fallback, ID deduplication, negative inactive clamping. No existing tests modified." }, { "guard_id": "GR-LANG-001", "status": "pass", "evidence": "All new PHP files follow PSR-4 namespace conventions. Import ordering auto-fixed by php-cs-fixer." }, { "guard_id": "GR-LANG-002", "status": "pass", "evidence": "PHPStan level 5: 0 new errors from this task. 4 pre-existing errors in AuthzUiContractTest.php are unrelated." } ], "commands": [ { "cmd": "docker compose exec php vendor/bin/phpunit --no-coverage", "result": "pass" }, { "cmd": "docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress", "result": "pass" }, { "cmd": "docker compose exec php vendor/bin/php-cs-fixer fix --dry-run --config=.php-cs-fixer.dist.php", "result": "pass" }, { "cmd": "docker compose exec php vendor/bin/phpunit --filter CoreStarterkitContractTest|ContainerFactoryContractTest", "result": "pass" }, { "cmd": "rg 'AuditMetadataEnricher' pages/admin/ (SC-001: usage in 4 edit action files)", "result": "pass" }, { "cmd": "rg 'GridUserCountEnricher' pages/admin/ (SC-002: usage in 3 data endpoint files)", "result": "pass" }, { "cmd": "rg 'created_by_label.*=.*trim' pages/ (SC-003: zero inline audit resolution left)", "result": "pass" } ], "quality_gate_results": [ { "gate_id": "QG-001", "result": "pass", "notes": "603 tests, 0 errors introduced by this task. 12 new tests added. 1 pre-existing failure (TranslationKeysTest: missing i18n key) — verified pre-existing: same failure reproduces on clean branch (git stash → phpunit → same failure). This task introduced zero test failures." }, { "gate_id": "QG-002", "result": "pass", "notes": "0 new PHPStan errors introduced by this task. 4 pre-existing errors in tests/Architecture/AuthzUiContractTest.php (nullable offset warnings) — verified pre-existing: present on clean branch before any task changes. This task introduced zero PHPStan errors." }, { "gate_id": "QG-003", "result": "pass", "notes": "Architecture contract tests (CoreStarterkitContractTest + ContainerFactoryContractTest): 24 tests, 6454 assertions, all green." }, { "gate_id": "QG-006", "result": "pass", "notes": "php-cs-fixer fix --dry-run: 0 of 526 files need fixing." } ], "test_results": [ { "name": "tests/Service/Audit/AuditMetadataEnricherTest.php", "result": "pass" }, { "name": "tests/Service/Data/GridUserCountEnricherTest.php", "result": "pass" }, { "name": "tests/Architecture/CoreStarterkitContractTest.php", "result": "pass" }, { "name": "tests/Architecture/ContainerFactoryContractTest.php", "result": "pass" } ], "open_items": [] }