ERP-21 worker for portal/dealer-portal host hard-cuts, duplicate-route retirement, and contract-proof cleanup.
NOTE: Startup and cleanup are handled by worker-base. This skill defines the WORK PROCEDURE.
Use for ERP-21 features that:
None.
mission.md, mission AGENTS.md, validation-contract.md, and the feature carefully..factory/services.yaml, .factory/library/architecture.md, .factory/library/environment.md, .factory/library/user-testing.md, and .factory/library/portal-split-hard-cut.md./api/v1/dealer-portal/**/api/v1/portal/finance/**/api/v1/portal/support/tickets/**/api/v1/dealer-portal/support/tickets/**/api/v1/support/**admin, accounting, or sales as applicable). Do not accept a dealer-only 403 as retirement proof.modules/accounting or db/migration_v2, update docs/approvals/R2-CHECKPOINT.md in the same feature.openapi.json when routes or verbs change.docs/endpoint-inventory.mderp-domain/docs/endpoint_inventory.tsv.factory/library/frontend-handoff.mddocs/frontend-api/README.mddocs/frontend-portals/accounting/README.md.factory/library/remediation-log.md when your feature removes duplicate-truth or dead code.features.json.MIGRATION_SET=v2 mvn compile -q from erp-domain/.MIGRATION_SET=v2 mvn test -Pgate-fast -Djacoco.skip=true unless the orchestrator has explicitly scoped the feature to a smaller temporary check during iteration.gate-fast is already red in the known unrelated O2C dispatch provenance lane before or during ERP-21 development:
.factory/services.yaml.curl probes showing:
Your handoff must include:
curl probes and test commands runyes or no){
"salientSummary": "Hard-cut internal finance onto `/api/v1/portal/finance/**` and retired the dealer/invoice/report duplicates that previously acted like alternate portal finance views. Rewrote the stale security/OpenAPI/docs coverage so the published contract now shows one internal host and one dealer host only.",
"whatWasImplemented": "Added `PortalFinanceController` with `/api/v1/portal/finance/ledger`, `/api/v1/portal/finance/invoices`, and `/api/v1/portal/finance/aging`, wired it to the existing dealer finance read models, and removed the duplicate dealer-finance routes from `DealerController`, `InvoiceController`, `AccountingController`, and `ReportController`. Replaced stale route-contract/security tests with canonical-host coverage, refreshed `openapi.json`, updated the endpoint inventories plus frontend handoff docs, and logged the duplicate-route retirement in `.factory/library/remediation-log.md`.",
"whatWasLeftUndone": "",
"verification": {
"commandsRun": [
{
"command": "cd erp-domain && MIGRATION_SET=v2 mvn -Djacoco.skip=true -Dtest='DealerPortalControllerSecurityIT,DealerControllerSecurityIT,InvoiceControllerSecurityContractTest,ReportControllerRouteContractIT,OpenApiSnapshotIT' test",
"exitCode": 0,
"observation": "Canonical-host and retired-route coverage passed after replacing the stale duplicate-route expectations."
},
{
"command": "cd erp-domain && MIGRATION_SET=v2 mvn compile -q",
"exitCode": 0,
"observation": "Compilation clean."
},
{
"command": "cd erp-domain && MIGRATION_SET=v2 mvn test -Pgate-fast -Djacoco.skip=true",
"exitCode": 0,
"observation": "Gate-fast passed."
},
{
"command": "bash scripts/guard_openapi_contract_drift.sh && bash scripts/guard_accounting_portal_scope_contract.sh",
"exitCode": 0,
"observation": "OpenAPI and accounting-portal scope guards passed."
}
],
"interactiveChecks": [
{
"action": "Reset runtime and curled `/api/v1/portal/finance/ledger` as seeded admin plus the retired `/api/v1/dealers/{dealerId}/ledger` route as seeded admin.",
"observed": "The canonical route returned 200 with tenant-bound finance data; the retired legacy route returned 404."
},
{
"action": "Curled `/api/v1/dealer-portal/invoices/{invoiceId}/pdf` for own invoice and then with a cross-dealer invoice id.",
"observed": "Own invoice PDF succeeded; cross-dealer probe returned 404."
}
]
},
"tests": {
"added": [
{
"file": "erp-domain/src/test/java/com/bigbrightpaints/erp/modules/portal/PortalFinanceControllerIT.java",
"cases": [
{
"name": "admin_can_read_portal_finance_hosts",
"verifies": "The canonical `/api/v1/portal/finance/**` subtree exists and is admin/accounting scoped."
},
{
"name": "retired_duplicate_finance_routes_return_not_found",
"verifies": "Legacy finance clones are absent even for formerly authorized actors."
}
]
}
]
},
"discoveredIssues": [
{
"severity": "medium",
"description": "A report-export doc outside the touched ERP-21 host split still references a retired dealer-aging path in a separate review packet.",
"suggestedFix": "Escalate to orchestrator only if the doc is inside the touched ERP-21 contract surface; otherwise keep ERP-21 scoped."
}
]
}