Files
breadcrumb-the-shire/agent-system/runs/SUPERGLOBAL-MIGRATION-001/plan.json
fs 9caa0a4f75 docs(agent): add SUPERGLOBAL-MIGRATION-001 run artifacts
Plan, execution report, guard review, acceptance review, and
finalize artifacts for the superglobal-to-abstraction migration
(87 pages migrated from $_SESSION/$_SERVER to
SessionStoreInterface/RequestRuntimeInterface).

Task: SUPERGLOBAL-MIGRATION-001

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 11:44:22 +01:00

182 lines
9.3 KiB
JSON

{
"task_id": "SUPERGLOBAL-MIGRATION-001",
"summary": "Migrate all pages from direct superglobal access ($_SESSION, $_SERVER) to framework abstractions (SessionStoreInterface, RequestRuntimeInterface). This resolves the pre-existing CoreStarterkitContractTest::testPagesUseRequestInputInsteadOfSuperglobals failure (GR-CORE-008, QG-003) that currently blocks 86 pages using $_SESSION and 2 pages using $_SERVER.",
"assumptions": [
"SessionStoreInterface is already registered in the DI container and available via app(SessionStoreInterface::class).",
"RequestRuntimeInterface is already registered in the DI container and provides method(), path(), ip(), userAgent(), isSecure().",
"No behavioral changes — this is a pure refactoring task replacing superglobal reads/writes with equivalent abstraction calls.",
"The architecture contract test (CoreStarterkitContractTest) already enforces the target state — passing it is the definition of done.",
"Pages that only read $_SESSION['user'], $_SESSION['current_tenant'], etc. can be migrated to $session->get('user'), $session->get('current_tenant').",
"Pages that write $_SESSION[...] = ... must use $session->set('key', value).",
"$_SERVER usage in pages/auth/login().php and pages/api/v1/auth/login().php is limited and can be replaced with RequestRuntimeInterface or RequestContext."
],
"scope": {
"in": [
"pages/**/*.php — all 86 files using $_SESSION directly",
"pages/auth/login().php — $_SERVER usage",
"pages/api/v1/auth/login().php — $_SERVER usage",
"tests/Architecture/CoreStarterkitContractTest.php — validation target (read-only)",
"lib/Http/SessionStoreInterface.php — reference for API surface",
"lib/Http/RequestRuntimeInterface.php — reference for API surface"
],
"out": [
"lib/Service/ — no service-layer changes (services already use abstractions)",
"lib/Repository/ — no repository changes",
"New features or behavior changes",
"Frontend JS/CSS changes",
"Database schema changes",
"Template/phtml view files (not checked by the contract test)"
]
},
"guardrails": {
"required_guard_ids": [
"GR-CORE-003",
"GR-CORE-008",
"GR-CORE-001"
],
"required_quality_gate_ids": [
"QG-001",
"QG-002",
"QG-003",
"QG-006"
]
},
"success_criteria": [
{
"id": "SC-001",
"criterion": "Zero $_SESSION, $_SERVER, $_COOKIE, $_POST, $_GET, $_FILES, $_REQUEST, REQUEST_METHOD superglobal references remain in pages/**/*.php."
},
{
"id": "SC-002",
"criterion": "CoreStarterkitContractTest::testPagesUseRequestInputInsteadOfSuperglobals passes (exit 0)."
},
{
"id": "SC-003",
"criterion": "Full PHPUnit suite passes (QG-001 exit 0) — no regressions introduced."
},
{
"id": "SC-004",
"criterion": "PHPStan level 5 passes (QG-002 exit 0) — no type errors from migration."
},
{
"id": "SC-005",
"criterion": "PHP-CS-Fixer passes (QG-006 exit 0) — all migrated files follow code style."
}
],
"implementation_steps": [
{
"id": "S1",
"title": "Audit SessionStoreInterface and RequestRuntimeInterface API surface",
"description": "Read SessionStoreInterface and RequestRuntimeInterface to map available methods (get, set, has, remove, etc.) and confirm they cover all superglobal access patterns found in pages. Document the mapping: $_SESSION['key'] → $session->get('key'), $_SESSION['key'] = val → $session->set('key', val), unset($_SESSION['key']) → $session->remove('key'), isset($_SESSION['key']) → $session->has('key'), $_SERVER['...'] → $request->method()/ip()/etc.",
"guard_refs": [
"GR-CORE-008"
]
},
{
"id": "S2",
"title": "Migrate auth pages (highest risk — login/register/reset/verify flows)",
"description": "Migrate pages/auth/*.php (login, register, forgot, reset, verify, verify-email) from $_SESSION to SessionStoreInterface and $_SERVER to RequestRuntimeInterface. These are security-critical paths — verify each migration preserves exact behavior. Files: pages/auth/login().php, pages/auth/register().php, pages/auth/forgot().php, pages/auth/reset().php, pages/auth/verify().php, pages/auth/verify-email().php.",
"guard_refs": [
"GR-CORE-008",
"GR-CORE-003"
]
},
{
"id": "S3",
"title": "Migrate API auth page",
"description": "Migrate pages/api/v1/auth/login().php from $_SERVER to RequestRuntimeInterface/RequestContext. This is the only API page with superglobal usage.",
"guard_refs": [
"GR-CORE-008",
"GR-CORE-003"
]
},
{
"id": "S4",
"title": "Migrate admin/users pages (bulk — 20+ files)",
"description": "Migrate all pages/admin/users/*.php from $_SESSION to SessionStoreInterface. This is the largest group (~20 files). Pattern is mostly $_SESSION['user']['id'], $_SESSION['current_tenant']['id'] reads.",
"guard_refs": [
"GR-CORE-008",
"GR-CORE-001"
]
},
{
"id": "S5",
"title": "Migrate admin/tenants pages",
"description": "Migrate all pages/admin/tenants/*.php from $_SESSION to SessionStoreInterface (~15 files).",
"guard_refs": [
"GR-CORE-008",
"GR-CORE-001"
]
},
{
"id": "S6",
"title": "Migrate admin core pages (settings, roles, permissions, departments)",
"description": "Migrate pages/admin/settings/*.php, pages/admin/roles/*.php, pages/admin/permissions/*.php, pages/admin/departments/*.php from $_SESSION to SessionStoreInterface.",
"guard_refs": [
"GR-CORE-008",
"GR-CORE-001"
]
},
{
"id": "S7",
"title": "Migrate admin audit and utility pages",
"description": "Migrate pages/admin/api-audit/*.php, pages/admin/import-audit/*.php, pages/admin/system-audit/*.php, pages/admin/user-lifecycle-audit/*.php, pages/admin/imports/*.php, pages/admin/scheduled-jobs/*.php, pages/admin/stats/*.php, pages/admin/mail-log/*.php, pages/admin/search/*.php, pages/admin/index().php from $_SESSION to SessionStoreInterface.",
"guard_refs": [
"GR-CORE-008",
"GR-CORE-001"
]
},
{
"id": "S8",
"title": "Migrate non-admin pages",
"description": "Migrate pages/address-book/*.php, pages/account/*.php, pages/search/*.php, pages/page/*.php, pages/index().php, pages/lang().php from $_SESSION to SessionStoreInterface.",
"guard_refs": [
"GR-CORE-008",
"GR-CORE-001"
]
},
{
"id": "S9",
"title": "Run all quality gates and verify contract test passes",
"description": "Execute QG-001 (full PHPUnit), QG-002 (PHPStan), QG-003 (CoreStarterkitContractTest specifically), QG-006 (CS check). All must exit 0. If any fail, fix and re-run.",
"guard_refs": [
"GR-CORE-008",
"GR-CORE-003"
]
}
],
"tests": [
"tests/Architecture/CoreStarterkitContractTest::testPagesUseRequestInputInsteadOfSuperglobals — must pass (currently fails with 86+2 violations)",
"tests/Architecture/CoreStarterkitContractTest::testServicesDoNotUseSuperglobals — must remain passing",
"QG-001: docker compose exec php vendor/bin/phpunit (full suite, exit 0)",
"QG-002: docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress (exit 0)",
"QG-003: docker compose exec php vendor/bin/phpunit tests/Architecture/CoreStarterkitContractTest.php (exit 0)",
"QG-006: docker compose exec php composer cs:check (exit 0)"
],
"acceptance_checks": [
"SC-001: grep -rl '$_SESSION\\|$_SERVER\\|$_COOKIE\\|$_POST\\|$_GET\\|$_FILES\\|$_REQUEST' pages/ --include='*.php' returns 0 results.",
"SC-002: CoreStarterkitContractTest::testPagesUseRequestInputInsteadOfSuperglobals exits 0 with 0 failures.",
"SC-003: Full PHPUnit suite exits 0 — no regressions.",
"SC-004: PHPStan level 5 exits 0 — no type errors.",
"SC-005: php-cs-fixer dry-run exits 0 — all files formatted."
],
"risks": [
{
"risk": "Session write patterns ($_SESSION['key'] = value) may not map 1:1 to SessionStoreInterface::set() if the interface has different semantics for nested keys.",
"mitigation": "Audit SessionStoreInterface thoroughly in S1. If nested access patterns like $_SESSION['user']['name'] exist, confirm whether $session->get('user')['name'] or $session->get('user.name') is the correct equivalent."
},
{
"risk": "86 files is a large blast radius — a subtle mistake could break auth or tenant scoping silently.",
"mitigation": "Migrate in batches by area (auth first, then admin/users, etc.). Run QG-001 after each batch to catch regressions early. Auth pages get extra scrutiny since they're security-critical."
},
{
"risk": "Some pages may use $_SESSION in ways that are not simple get/set (e.g., array manipulation, unset, reference assignment).",
"mitigation": "In S1, categorize all access patterns before starting migration. Flag complex patterns for manual review."
},
{
"risk": "$_SERVER usage may include keys not covered by RequestRuntimeInterface (e.g., $_SERVER['HTTP_HOST'], $_SERVER['DOCUMENT_ROOT']).",
"mitigation": "Audit the 2 $_SERVER pages in S1 to identify exact keys used. If RequestRuntimeInterface doesn't cover them, use RequestContext or add a targeted method."
}
]
}