PLUTO-22 ·
plutoPluto P2: accessRequests.status unconstrained text — add CHECK IN (pending/needs_info/approved/rejected)
- Ref
PLUTO-22(#885)- Project
pluto- Status
- done
- Priority
- normal
- Type
- task
- Assigned
- — db
- Created by
- wi-cli-venus
- Created
- 2026-06-10T05:12:00.474Z
- Updated
- 2026-06-10T07:44:51.926Z
- Closed
- 2026-06-10T07:44:51.926Z
Questions
No questions.
Event log
-
DESIGN CONFLICT: Mars recommends CHECK IN(...), but Pluto §Lookups bans CHECK on enumerated label sets (native-enum-in-disguise). Correct Pluto fix = lookupOptions grupo accessRequestStatus + FK, OR keep text validated in app. Held pending pm-mars reconciliation; do NOT dispatch the CHECK as written.
-
DESIGN RESOLVED (pm-mars aligned): FK-only, NOT a CHECK. Add statusOptionId uuid NOT NULL FK→lookupOptions(id); seed grupo accessRequestStatus = pending(isDefault)/needs_info/approved/rejected; migrate existing rows by status-text→optionId; DROP plain status text col (no dual-carry, cleaner than Mars). accessRequests is trigger-archived → migration sets archive sentinel context; repoint any app readers of .status to FK/lookup BEFORE drop. Schema WI: audit pre-impl design-ping + pre-push diff. Queued behind 012 + PLUTO-23 (db lane).
-
Design resolved (FK-only); queued behind 012 + PLUTO-23 in db lane.
-
Plan REVISED (audit BLOCK:014-design): db's grep missed the WRITER. Public access-request form auth-actions.ts:474-483 INSERTs status='pending' w/o statusOptionId → Phase-1 NOT NULL would 500 the public signup form. Restructured (remediation A, PLUTO-18-style): Ph1(014)=add statusOptionId NULLABLE+seed grupo+backfill 49 rows+FK, KEEP status, NO NOT NULL. Ph2(coder)=repoint 11 sites (10 readers + the auth-actions.ts WRITER), confirm live. Ph3(015)=NOT NULL + DROP status, hard-gated on Ph2-live. 2nd live-path catch this session (cf getAuditLog/PLUTO-18).
-
Phase 1 pushed: SHA 6ad06b2 (014.sql nullable statusOptionId + grupo seed + 49-row backfill + nullable FK, schema export). Stray 5523c0f = package.json-only side-effect of the stash collision (harmless, both on main, 6ad06b2 carries artifacts). audit post-push pending (verify public signup form unaffected by the added nullable col). On Phase-1-live PASS → dispatch coder Phase 2 (repoint 11 sites incl. auth-actions.ts writer).
-
Phase 1 LIVE — audit PASS:6ad06b2 (public signup form unaffected by nullable statusOptionId). Phase 2 (coder, 11-site repoint) unblocked. Phase 3 (015 NOT NULL + DROP) gated on Phase-2-live.
-
Ph2 scope CORRECTED by coder recon (2 spec errors caught before impl): (1) lookupOptions has NO English label col — only Spanish nombre (Pendiente/Requiere información/Aprobado/Rechazado); subselects key on nombre (convention-consistent w/ estadoRevision). (2) real scope ~25-30 touchpoints/8 files, not 11 — db's grep undercounted the READ layer (5 read-path SELECTs exposing ar.status + ~9 more SQL WHERE/SELECT + ~15 TSX/JS readers); getAuditLog-class undercount. APPROVED approach: writers→statusOptionId (nombre subselect, clean cut), WHERE status IN→statusOptionId IN(nombre subselects), read SELECTs→derive English status alias via CASE lo.nombre + JOIN lookupOptions (preserves .status=== JS contract → 15 readers UNTOUCHED + Phase-3-safe), expose lo.nombre AS statusLabel for display :470. Full audit pre-push diff (breadth). Push held for PASS:6d8c58b.
-
Ph1 LIVE+PASS:6ad06b2 (nullable statusOptionId + 49-row backfill + grupo accessRequestStatus seeded). Ph2 in progress: coder repointing ~25-30 read sites/8 files + the public signup writer (auth-actions.ts) via new src/lib/access-request-status-sql.ts (nombre-keyed subselects + CASE→English-code derive). Push held for audit pre-push full diff review. Ph3 (mig 015 NOT NULL + DROP status) gated on Ph2 confirmed live + joint VIEW/trigger/SQL-fn grep.
-
Ph2 LIVE-pending: pushed b6e267c (v1.67.21) — solo, clean git-status gate, build green, audit PASS pre-push + padEnd null-guard. App repoint: writers→statusOptionId, readers derive English status via CASE, raw status text left stale (no dual-write), display→Spanish statusLabel. Static pre-Ph3 grep clean: jsonb archive (DROP just stops emitting key, no trigger break), zero accessRequestsArchive app readers, no app VIEW reads status. NEW Ph3 prereq (audit): uq_accessRequests_open_email is the ATOMIC open-request dedup guard (partial UNIQUE ON canonicalizeEmail(email) WHERE status IN pending/needs_info; app dup-check non-atomic). 015 DROP status auto-drops it → MUST recreate on statusOptionId with LIVE-seeded literal UUIDs (Pendiente + Requiere información). Ph3 release gated on: audit post-push PASS:b6e267c + 015 staged WITH index recreate + joint live-catalog grep. Transient gap: stale text-index freezes approved/rejected as pending → spurious unique-violation possible on reject-then-resubmit-same-email until 015; bounded (no real users), Elazar advised.
-
Fully closed — expand/migrate/contract complete & live. Ph1 6ad06b2 (nullable statusOptionId + grupo seed + 49-row backfill). Ph2 b6e267c (app repoint: writers→statusOptionId, readers derive English status via CASE, Spanish statusLabel display; PASS pre+post-push). Ph3 015 3e1df2c (interim backfill + DROP old uq index + SET NOT NULL + DROP COLUMN status + recreate uq_accessRequests_open_email on statusOptionId with live UUIDs Pendiente=81158d41/Requiere-info=26a57005; PASS:3e1df2c, deploy READY, 0 runtime errors). Joint live-catalog grep clean (0 fn/view/trigger read raw status). Atomic open-request dedup preserved. Audit process note logged: route irreversible-DROP .sql for pre-apply review (see memory). Cumulative head 3e1df2c → Mars round-2 delta-re-audit target.