# ADR-006: verify_pin RPC Returns a TABLE Array, Not a Success Boolean

## Status

Accepted, 2026-06-25.

## Status History

```yaml
status_history:
  - date: 2026-06-25
    status: Proposed
    changed_by: hkl
    reason: Formalising API contract that caused multiple integration bugs
    changed_via: adr-kit (360lm)
  - date: 2026-06-25
    status: Accepted
    changed_by: hkl
    reason: Contract stable; all PWAs now use correct check pattern
    changed_via: adr-kit (360lm)
```

## Context

`verify_pin` is a PostgreSQL RPC function called via PostgREST by every PWA that uses PIN-based authentication. The function is defined with `RETURNS TABLE (id int, name text, role text)`. PostgREST wraps all `RETURNS TABLE` results in a JSON array, even when there is exactly one matching row. Early PWA integrations incorrectly assumed the response was `{success: true, id: ..., name: ..., role: ...}` (an object), causing `res.id` to return `undefined` and login to always fail silently. The correct check is `Array.isArray(res) && res.length > 0`, then read `res[0].id`, `res[0].name`, `res[0].role`.

## Decision

All PWA callers of `verify_pin` MUST check the response as an array:
```javascript
const res = await apiPost('/rpc/verify_pin', { pin });
const user = Array.isArray(res) ? res[0] : null;
if (!user?.id) { /* PIN wrong */ }
```
Never check `res.success` or `res.id` directly on the raw response.

**Decision Maker:** hkl

## Alternatives Considered

- **Rewrite verify_pin to return a JSON object with RETURNS JSON.** Rejected: would require migrating all existing callers; PostgREST's TABLE array convention is consistent and correct for the framework — the callers should adapt, not the DB function.
- **Add a wrapper RPC that returns a single object.** Rejected: adds a redundant DB function with no benefit; the correct array check is a one-liner.
- **Return HTTP 401 on wrong PIN instead of empty array.** Rejected: PostgREST error codes require different error-handling paths; empty array on wrong PIN is clean and consistent with the TABLE return type.

## Consequences

**Positive:**
- Consistent with PostgREST's documented behaviour for `RETURNS TABLE` functions.
- Empty array on wrong PIN is unambiguous — no need to inspect error codes.
- `res[0]` gives the full user record in one step.

**Negative / Trade-offs:**
- Counterintuitive for developers expecting a REST-style `{success: bool}` response.
- Must document this explicitly — easy to get wrong on a new PWA.

**Risks and mitigations:**
- New PWA developer uses `res.success` check: silent login failure, hard to debug. Mitigated: this ADR + code review checklist.

## Related Decisions

- None.

## References

- `memory/feedback_verify_pin_response.md` — original rule capture
- PostgREST docs: RETURNS TABLE functions always produce JSON arrays
