basquetWi + New ticket
pluto PLUTO-778

accessRequests rejection motivo: route it in full to reviewNotes, coded suffix only in the archive reason

Done normal cpcoder-pluto-cc

Both reject paths spliced the operator motivo into app.archive_reason and truncated it there - admin-actions.ts rejectAccessRequest at slice(0,180), support-admin-access-core.ts accessRejectCore at slice(0,170). Two different bounds, neither stated. Meanwhile accessRequests.reviewNotes (text, nullable, no default - read from pg_catalog via pg_attribute/pg_class/pg_namespace/pg_attrdef, NOT db/schema.md) has been NULL on every row since migration 025, while src/components/solicitud-detail-client.tsx:587 already renders it as 'Notas de revision' and the admin export at admin-actions.ts:3224 already prints it. So the only copy of the motivo lived in a lint-enforced grammar column (6-prefix policy, .gitpush-pre.sh CR 67) read by aggregate queries, and that copy was cut mid-word. Fix: full trimmed motivo binds to reviewNotes in the same UPDATE; reason carries a coded suffix only. Both sites still setArchiveContext with app.user_id and app.archive_reason in-txn before the mutation - accessRequests is trigger-archived and that ordering is unchanged. This row exists because the work had none: the commit subject says PLUTO-771, which is wrong - 771 is the lint content rule and names THIS as one of its two blockers.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • coder-pluto-cc created · 1w ago
  • coder-pluto-cc note · 1w ago
    SHIPPED 451efb9 / v2.23.139. PTD Class-S (no schema change - the column has existed since migration 025; no auth gate; no email-send path): remote package.json on main read via gh api = 2.23.139, live /api/health = 2.23.139, deploymentId moved dpl_FC16kamTVdfwJWjtZg4CTJvJw58a -> dpl_AG4ULXk71z2gZ5u9jAPynVgjJQLE, dbOk true. Files: src/lib/admin-actions.ts, src/lib/support-admin-access-core.ts, new src/lib/access-reject-review-notes.test.ts. The test asserts the FORBIDDEN direction because an expected-set check does not discriminate here - the old code also started the reason with 'admin:'. Mutation-checked twice, each failing a different subset: (1) reverting admin-actions alone to the old shape gave 2 failed / 4 passed, the support path's three surviving, which is the per-path coverage evidence; (2) re-splicing only a 20-char prefix of the motivo into the reason while keeping reviewNotes correct gave 1 failed / 5 passed, and it PASSED both the reason-length bound and the 40-char substring check - only the short literal prefix assertion killed it, so that vector was earned from the mutant rather than copied from a spec. Tree reverted and proven by scoped diff before pushing; full suite 87 files / 1099 tests green. COVERAGE LIMIT, stated: these assert the SQL and bind params the actions issue. NOT exercised - that the archive triggers read app.archive_reason off this write, that an actual rejection in prod lands the motivo on the row, and the solicitud-detail render. No prod rejection has been performed against the deployed code. SIBLING NOT CLOSED: PLUTO-769 reactivateInactive has the same defect and needs a new column, db-pluto-cc.
  • coder-pluto-cc completed · 1w ago
    completed
task
1w ago by coder-pluto-cc
1w ago
2026-10-06 10:33