Symptom
On the Plans page, the "Planned Purchases" section fails to load with "Failed to load planned purchases: Internal server error" (HTTP 500). Reproducible by the Admin user, so this is not a permissions issue.
Root Cause
GetPlannedExecutions in internal/config/store_postgres.go projects only 26 columns in its SELECT, omitting scheduled_execution_at. The shared scanExecutionRows helper scans 27 columns, with &scheduledExecutionAt as the final (27th) scan target. Against a real PostgreSQL instance, the row Scan fails with "expected 27 destination arguments in Scan, not 26", returning "failed to scan execution" - which the handler surfaces as a 500.
This drifted in via PR #804 (revocation-delay feature, commit 8e5f139) which added scheduled_execution_at to scanExecutionRows and every other SELECT feeding it, but skipped GetPlannedExecutions.
The existing test TestPGXMock_GetPlannedExecutions_ProjectsAllScanColumns was a false positive: its mock ExpectQuery regexp only checked the SQL contains "idempotency_key" and returned a 27-column result regardless of the actual projection, so it passed even with the bug present.
Fix
- Add
scheduled_execution_at to the GetPlannedExecutions SELECT in the correct position (after idempotency_key, matching scanExecutionRows order).
- Tighten the regression test's regexp to require both
idempotency_key AND scheduled_execution_at appear in the SQL, so a future column drift is caught immediately.
Symptom
On the Plans page, the "Planned Purchases" section fails to load with "Failed to load planned purchases: Internal server error" (HTTP 500). Reproducible by the Admin user, so this is not a permissions issue.
Root Cause
GetPlannedExecutionsininternal/config/store_postgres.goprojects only 26 columns in its SELECT, omittingscheduled_execution_at. The sharedscanExecutionRowshelper scans 27 columns, with&scheduledExecutionAtas the final (27th) scan target. Against a real PostgreSQL instance, the row Scan fails with "expected 27 destination arguments in Scan, not 26", returning "failed to scan execution" - which the handler surfaces as a 500.This drifted in via PR #804 (revocation-delay feature, commit 8e5f139) which added
scheduled_execution_attoscanExecutionRowsand every other SELECT feeding it, but skippedGetPlannedExecutions.The existing test
TestPGXMock_GetPlannedExecutions_ProjectsAllScanColumnswas a false positive: its mock ExpectQuery regexp only checked the SQL contains "idempotency_key" and returned a 27-column result regardless of the actual projection, so it passed even with the bug present.Fix
scheduled_execution_atto theGetPlannedExecutionsSELECT in the correct position (afteridempotency_key, matchingscanExecutionRowsorder).idempotency_keyANDscheduled_execution_atappear in the SQL, so a future column drift is caught immediately.