Files
breadcrumb-the-shire/agent-system/runs/CODE-DEDUP-REPOSITORY-001/plan.json

125 lines
5.5 KiB
JSON
Raw Normal View History

2026-03-13 12:05:34 +01:00
{
"task_id": "CODE-DEDUP-REPOSITORY-001",
"summary": "Extract repeated repository boilerplate (ID extraction, array sanitization, unwrap/normalization) into shared support utilities to eliminate ~290 lines of duplication across 6+ repository files.",
"assumptions": [
"MintyPHP DB layer returns nested arrays with table-name keys (e.g. $row['tenants']).",
"All repositories use the same unwrap, unwrapList, extractIds, and sanitizePositiveIds patterns.",
"A trait or static helper class is the right abstraction — no base repository class needed (repositories are thin)."
],
"scope": {
"in": [
"lib/Repository/Tenant/TenantRepository.php — unwrap, unwrapList, listIds extraction",
"lib/Repository/Access/RoleRepository.php — unwrap, unwrapList, listIds extraction",
"lib/Repository/Org/DepartmentRepository.php — unwrap, unwrapList, listIds extraction",
"lib/Repository/Access/PermissionRepository.php — ID extraction patterns",
"lib/Repository/Access/UserRoleRepository.php — ID sanitization",
"lib/Repository/Org/UserDepartmentRepository.php — ID sanitization",
"New file: lib/Repository/Support/RepositoryArrayHelper.php"
],
"out": [
"Repository method signatures (public API unchanged)",
"Repository SQL queries (not touched)",
"Service layer changes",
"Frontend changes"
]
},
"guardrails": {
"required_guard_ids": [
"GR-CORE-001",
"GR-LANG-001",
"GR-LANG-002",
"GR-TEST-001",
"GR-TEST-002"
],
"required_quality_gate_ids": [
"QG-001",
"QG-002",
"QG-003",
"QG-006"
]
},
"success_criteria": [
{
"id": "SC-001",
"criterion": "A single RepositoryArrayHelper class exists in lib/Repository/Support/ providing extractIds(), sanitizePositiveIds(), unwrap(), and unwrapList() as static methods."
},
{
"id": "SC-002",
"criterion": "All 6+ repository files use RepositoryArrayHelper instead of inline implementations. No duplicate unwrap/extractIds/sanitize logic remains."
},
{
"id": "SC-003",
"criterion": "Repository public method signatures and return values are identical before and after refactoring (pure internal refactor)."
},
{
"id": "SC-004",
"criterion": "PHPUnit, PHPStan, Architecture Contract, and CS checks pass green; zero new failures introduced by this task (pre-existing failures are out of scope)."
2026-03-13 12:05:34 +01:00
}
],
"implementation_steps": [
{
"id": "S1",
"title": "Create RepositoryArrayHelper",
"description": "Create lib/Repository/Support/RepositoryArrayHelper.php with static methods: extractIds(array $rows, string $tableKey): array, sanitizePositiveIds(array $ids): array, unwrap(?array $row, string $tableKey): ?array, unwrapList(mixed $rows, string $tableKey): array.",
"guard_refs": ["GR-CORE-001", "GR-LANG-001"]
},
{
"id": "S2",
"title": "Write unit tests for RepositoryArrayHelper",
"description": "Test all 4 methods with edge cases: empty arrays, null input, missing table keys, mixed types, duplicate IDs, negative IDs.",
"guard_refs": ["GR-TEST-001", "GR-TEST-002"]
},
{
"id": "S3",
"title": "Refactor TenantRepository",
"description": "Replace inline unwrap/unwrapList/extractIds with RepositoryArrayHelper calls. Verify no signature changes.",
"guard_refs": ["GR-CORE-001"]
},
{
"id": "S4",
"title": "Refactor RoleRepository and PermissionRepository",
"description": "Replace inline implementations with RepositoryArrayHelper calls.",
"guard_refs": ["GR-CORE-001"]
},
{
"id": "S5",
"title": "Refactor DepartmentRepository and UserDepartmentRepository",
"description": "Replace inline implementations with RepositoryArrayHelper calls.",
"guard_refs": ["GR-CORE-001"]
},
{
"id": "S6",
"title": "Refactor UserRoleRepository",
"description": "Replace inline ID sanitization with RepositoryArrayHelper::sanitizePositiveIds().",
"guard_refs": ["GR-CORE-001"]
},
{
"id": "S7",
"title": "Run all quality gates",
"description": "QG-001 PHPUnit, QG-002 PHPStan, QG-003 Architecture, QG-006 CS check.",
"guard_refs": ["GR-LANG-002"]
}
],
"tests": [
"tests/Repository/Support/RepositoryArrayHelperTest.php — new, covers all 4 static methods with edge cases",
"tests/Architecture/CoreStarterkitContractTest.php — must stay green",
"Existing service tests that call repository methods indirectly — must stay green"
],
"acceptance_checks": [
"SC-001: File lib/Repository/Support/RepositoryArrayHelper.php exists with 4 public static methods",
"SC-002: rg 'foreach.*\\$row.*\\[.*id.*\\]' lib/Repository/ returns only RepositoryArrayHelper, not inline implementations",
"SC-003: git diff shows no changes to public method signatures in repository files",
"SC-004: QG-001 + QG-002 + QG-003 + QG-006: zero new failures introduced by this task (pre-existing failures are out of scope)"
2026-03-13 12:05:34 +01:00
],
"risks": [
{
"risk": "Subtle behavioral difference in edge cases between inline and helper implementations",
"mitigation": "Write comprehensive helper tests first (TDD). Run full QG-001 after each repository file change."
},
{
"risk": "Table key naming inconsistency across repositories",
"mitigation": "Audit all unwrap calls first to confirm table key naming. The helper accepts the key as parameter, so naming differences are handled."
}
]
}