# Phase 4 — Deferred Fixes & DB/Code Alignment **Goal:** clear the items Phase 3 deliberately preserved or surfaced, and which are real behavioral defects once the code runs against the live PostgreSQL at `PG_HOST`. **No endpoint or JSON shape changes** unless a stage explicitly declares one and updates the docs/READMEs accordingly. **Prerequisite:** Phase 3 module split landed (repo layer, bootstrap `index.js`, `/bus/` + legacy alias mounts, `search_path="transit.bus"`). ## 1. Verified-failing items (triage from Phase 3 verification) | # | Item | Where | Current behavior | Why it matters | | --- | --- | --- | --- | --- | | 1 | `GET /bus/schedules` → 500 `column s.bus_id does not exist` | `repo/schedules.js` list query | Query expects a `bus_id` column the live DB lacks | The core read endpoint is broken on the live DB in both old and new code | | 2 | Mock `markStopPassed` → 500 `delayMinutes is not defined` | `repo/schedules.js` / `.mock.js` | Mock branch reads an undeclared variable | `/driver/schedules/:id/stops/:order/passed` always 500s in mock mode | | 3 | `bulk` endpoints + lines reorder/open `db.pool.connect()` before `try` | `repo/weekly.js`, `repo/adminSchedules.js`, `repo/lines.js` | With PG unreachable they hang instead of failing fast | Production blast-radius if the DB flaps | | 4 | Dead `overview` enrichment branch | original handler; NOT copied to `repo/schedules.mock.js` | Unreachable code in original | Left as-is during Phase 3; decide delete or rework | | 5 | Legacy root-alias mount | `index.js` (Double-mount `/` + `Deprecation` header) | Serves every route twice | Only Windows XP driver still needs it; plan its removal | ## 2. Rules 1. One fix per stage; verify against **live DB** where the stage touches PG. 2. Every mock-side fix MUST be mirrored with identical behavior in the PG branch (and vice versa) so both modes stay byte-identical for the same logical input. 3. Do not normalize mock vs PG response casing (that was the Phase 3 contract); fix *fairness* (both modes behave alike), not shape. 4. Any endpoint whose JSON shape must change requires a doc update in this file and in `transit_api/README.md`, and gets a note for the consuming clients (`admin_ui`, `monitoring_ui`, `windows_xp_driver_ui`). 5. `node --check` + `grep -rn DEV_MOCK index.js routes/` (must stay clean) after every stage. ## 3. Stages ### Stage A — alive `schedules` read path (DB/query alignment) - Inspect real schema: `\d "transit.bus".schedules` (and `shifts`) at `PG_HOST`. Determine whether `bus_id` was renamed/never added and whether the code or the data is canonical (other clients: `admin_ui`, `monitoring_ui` also read schedules — check what columns they rely on). - Decide: (a) add/migrate the column (`ALTER TABLE` + backfill from `bus_line_id`/related), or (b) adjust the query. Prefer fixing the data model so the API and all consumers see one shape. - Re-run the Phase 3 live parity sweep; `GET /bus/schedules*` must now return 200 with real rows in BOTH original-equivalent and refactored code paths. - Gate: `GET /bus/schedules`, `/bus/schedules/overview`, `/bus/schedules/:id` all 200 on live DB; `GET /bus/schedules/recurring` unchanged in response shape if it already worked. ### Stage B — mock `markStopPassed` fairness - Fix the undeclared `delayMinutes` read in the mock branch (compute the same duration the PG branch derives from the `schedule_stop_progress` row/stop times). Produces 200 instead of 500 in mock mode, matching PG mode. - Gate: harness2 (mock mode) for `POST .../passed` → 200; PG mode unchanged. ### Stage C — fail-fast PG connects - Move `db.pool.connect()` inside `try` for the open-connect endpoints so an unreachable DB yields the same 500/timeout the non-open endpoints already do; preserve short-circuit ordering so `try` + connect can't double-acquire. - Verify order/behavior parity pre/post on live DB with PG up; with PG down the endpoint fails fast instead of hanging. - Gate: same responses as Phase 3 harness when PG reachable; NEW: explicit PG-down test shows quick 500 (differential documented here). ### Stage D — dead-code cleanup - Delete the unreachable `overview` enrichment in the original-style handler (now only exists as the pg-branch / historical code); confirm no hidden column the live DB lacks was being referenced only there. - Recommend: keep the `schedule_stop_progress` upsert the pg branch needs; remove nothing else. - Gate: `grep` clean; overview 200 on live DB. ### Stage E — retire legacy alias (deferred decision) - Reconfirm at project level whether the Windows XP driver is still deployed (`windows_xp_driver_ui/driver_xp.c`). If yes: **do not do this stage**, keep the `Deprecation` header and re-schedule. If no: remove the `/` double-mount from `index.js`, add 404 for legacy paths, update `BUS_API_PREFIX_REFACTOR.md`. - Gate: `GET /schedules` → 404; `GET /bus/schedules` → 200; no route uses `/`. ## 4. Verification (gate after every stage) ```bash cd transit_api node --check index.js && node --check lib/*.js routes/*.js repo/*.js mock/store.js grep -rn DEV_MOCK index.js routes/ || echo "clean" # live DB (PG at .env PG_HOST): node index.js # prod curl -s http://localhost:5001/health # database:"ok" curl -s http://localhost:5001/bus/schedules # stage A: 200 JSON # mock: DEV_MOCK=1 node index.js # stage B/C mock fairness ``` Re-run `/tmp/opencode/live-parity.js` (read-only old-vs-new) and the Phase 3 harness after each stage; all prior byte-parity results must stay green except for the specific fix the stage documents. ## 5. Definition of done 1. `GET /bus/schedules`, `.overview`, `/:id`, recurring all 200 on live DB. 2. Mock and PG modes behave identically for every endpoint (harness, not just shape). 3. PG-down produces fast, clear 500s (no hangs) on the connect-before-try endpoints. 4. No dead code; legacy alias decision recorded in this repo. 5. Per-stage differential reports appended here.