# Instructions

- Following Playwright test failed.
- Explain why, be concise, respect Playwright best practices.
- Provide a snippet of code with the fix, if possible.

# Test info

- Name: counters.spec.js >> Counters — E2E supervisor flow >> Phase 4.7 — audit log: consume_invite logs login, client_log_view logs view, client_set_response logs response, supervisor RPC gated + filterable
- Location: tests/counters.spec.js:904:3

# Error details

```
Error: expect(received).toBe(expected) // Object.is equality

Expected: true
Received: undefined
```

# Test source

```ts
  835  |     const mailRow = await (await ctx.get(
  836  |       `${DB}/mail_outbox?reference=eq.notify-${cuRow.notify_id}`,
  837  |       { headers: { 'Accept-Profile': 'counters' }})).json();
  838  |     expect(mailRow).toHaveLength(1);
  839  |     expect(mailRow[0].to_email).toBe(cuEmail);
  840  |     expect(mailRow[0].subject).toBe('P46 spec subject');
  841  | 
  842  |     // Re-dispatching the same row → 'not_pending'
  843  |     const re = await (await ctx.post(`${DB}/rpc/dispatch_notify`, { headers: HC,
  844  |       data: JSON.stringify({
  845  |         p_notify_id: cuRow.notify_id, p_subject: 'x', p_body_text: 'x', p_body_html: 'x',
  846  |       }),
  847  |     })).json();
  848  |     expect(re).toEqual({ ok: false, error: 'not_pending' });
  849  | 
  850  |     // admin_list_notifications — supervisor sees the supervisor row
  851  |     const list = await (await ctx.post(`${DB}/rpc/admin_list_notifications`, { headers: HC,
  852  |       data: JSON.stringify({ p_supervisor_id: 'harish', p_limit: 100 }),
  853  |     })).json();
  854  |     expect(list.find(n => Number(n.notify_id) === Number(supRow.notify_id))).toBeTruthy();
  855  | 
  856  |     // Non-supervisor → empty (NOT IN supervisor allow-list)
  857  |     const denied = await (await ctx.post(`${DB}/rpc/admin_list_notifications`, { headers: HC,
  858  |       data: JSON.stringify({ p_supervisor_id: 'mukesh', p_limit: 100 }),
  859  |     })).json();
  860  |     expect(Array.isArray(denied)).toBe(true);
  861  |     expect(denied).toHaveLength(0);
  862  | 
  863  |     // admin_mark_notification_seen on supervisor row → status flips to 'suppressed'
  864  |     const mark = await (await ctx.post(`${DB}/rpc/admin_mark_notification_seen`, { headers: HC,
  865  |       data: JSON.stringify({ p_supervisor_id: 'harish', p_notify_id: supRow.notify_id }),
  866  |     })).json();
  867  |     expect(mark.ok).toBe(true);
  868  |     const supAfter = await (await ctx.get(`${DB}/notify_queue?notify_id=eq.${supRow.notify_id}`,
  869  |       { headers: { 'Accept-Profile': 'counters' }})).json();
  870  |     expect(supAfter[0].status).toBe('suppressed');
  871  | 
  872  |     // Non-supervisor mark_seen → forbidden
  873  |     const fz = await (await ctx.post(`${DB}/rpc/admin_mark_notification_seen`, { headers: HC,
  874  |       data: JSON.stringify({ p_supervisor_id: 'mukesh', p_notify_id: supRow.notify_id }),
  875  |     })).json();
  876  |     expect(fz).toEqual({ ok: false, error: 'forbidden' });
  877  | 
  878  |     // client_response trigger: client_status change creates a supervisor-row
  879  |     await ctx.patch(`${DB}/submissions?sub_id=eq.${subId}`, { headers: HR_PMIN,
  880  |       data: JSON.stringify({ client_status: 'approved', client_approved_by: 'p46-client' }),
  881  |     });
  882  |     const respRows = await (await ctx.get(
  883  |       `${DB}/notify_queue?payload->>sub_id=eq.${subId}&event_type=eq.client_response`,
  884  |       { headers: { 'Accept-Profile': 'counters' }})).json();
  885  |     expect(respRows).toHaveLength(1);
  886  |     expect(respRows[0].status).toBe('dispatched');
  887  |     expect(respRows[0].recipient_type).toBe('supervisor');
  888  | 
  889  |     // Cleanup
  890  |     const HCd = { headers: { ...HC, Prefer: 'return=minimal' } };
  891  |     const HRd = { headers: { ...HR, Prefer: 'return=minimal' } };
  892  |     await ctx.delete(`${DB}/submissions?sub_id=eq.${subId}`, HRd);
  893  |     await ctx.delete(`${DB}/notify_queue?payload->>sub_id=eq.${subId}`, HCd);
  894  |     await ctx.delete(`${DB}/notify_queue?recipient_email=eq.${cuEmail}`, HCd);
  895  |     await ctx.delete(`${DB}/mail_outbox?to_email=eq.${cuEmail}`, HCd);
  896  |     await ctx.delete(`${DB}/client_session?client_user_id=eq.${cuId}`, HCd);
  897  |     await ctx.delete(`${DB}/client_invite?invite_id=eq.${inviteId}`, HCd);
  898  |     await ctx.delete(`${DB}/client_user?client_user_id=eq.${cuId}`, HCd);
  899  |     await ctx.delete(`${DB}/client?client_id=eq.${clientId}`, HCd);
  900  |     await ctx.delete(`${DB}/counter?counter_id=eq.${counterId}`, HCd);
  901  |     await ctx.dispose();
  902  |   });
  903  | 
  904  |   test('Phase 4.7 — audit log: consume_invite logs login, client_log_view logs view, client_set_response logs response, supervisor RPC gated + filterable', async () => {
  905  |     const ctx = await request.newContext();
  906  |     const HC = { 'Accept-Profile': 'counters', 'Content-Profile': 'counters', 'Content-Type': 'application/json' };
  907  |     const HC_PMIN = { ...HC, Prefer: 'return=minimal' };
  908  |     const HR = { 'Accept-Profile': 'recce',    'Content-Profile': 'recce',    'Content-Type': 'application/json' };
  909  |     const HR_PMIN = { ...HR, Prefer: 'return=minimal' };
  910  |     const stamp     = Date.now().toString(36).slice(-6);
  911  |     const brand     = `P47_${stamp.toUpperCase()}`;
  912  |     const clientId  = `cli-p47-${stamp}`;
  913  |     const cuEmail   = `p47-${stamp}@spec.test`;
  914  |     const counterId = `cntr-p47-${stamp}`;
  915  |     const subId     = `sub-p47-${stamp}`;
  916  | 
  917  |     // Seed counter
  918  |     await ctx.post(`${DB}/counter`, { headers: HC_PMIN, data: JSON.stringify({
  919  |       counter_id: counterId, display_name: `P47 ${stamp}`, address_line1: '1 P47',
  920  |       pincode: '160001', created_by: 'pw-p47',
  921  |     })});
  922  | 
  923  |     // Seed client + invite (creates active client_user)
  924  |     await ctx.post(`${DB}/client`, { headers: HC_PMIN, data: JSON.stringify({
  925  |       client_id: clientId, name: `P47 Brand ${stamp}`, brand_codes: [brand],
  926  |       created_by: 'pw-p47',
  927  |     })});
  928  |     const inv = await (await ctx.post(`${DB}/rpc/invite_client_user`, { headers: HC,
  929  |       data: JSON.stringify({
  930  |         p_email: cuEmail, p_client_id: clientId, p_role: 'SM',
  931  |         p_scope_kind: 'all', p_scope_values: [], p_display_name: 'P47',
  932  |         p_invited_by: 'harish',
  933  |       }),
  934  |     })).json();
> 935  |     expect(inv.ok).toBe(true);
       |                    ^ Error: expect(received).toBe(expected) // Object.is equality
  936  |     const cuId     = inv.client_user_id;
  937  |     const inviteId = inv.invite_id;
  938  | 
  939  |     // Submission marked official so the visibility view exposes it to the client_user
  940  |     await ctx.post(`${DB}/submissions`, { headers: HR_PMIN, data: JSON.stringify({
  941  |       sub_id: subId, store_name: `P47 Store`, brand, visit_date: '2026-06-14',
  942  |       counter_id: counterId, submitted_by: 'harish',
  943  |       is_official_for_client: true, official_picked_by: 'harish',
  944  |     })});
  945  | 
  946  |     // ── 1. consume_invite → 'login' audit row
  947  |     const cons = await (await ctx.post(`${DB}/rpc/consume_invite`, { headers: HC,
  948  |       data: JSON.stringify({ p_invite_id: inviteId, p_ip: '10.0.0.7', p_user_agent: 'PW/4.7' }),
  949  |     })).json();
  950  |     expect(cons.ok).toBe(true);
  951  |     const sessionId = cons.session_id;
  952  | 
  953  |     // ── 2. client_log_view → 'recce_view' audit row
  954  |     const lv = await (await ctx.post(`${DB}/rpc/client_log_view`, { headers: HC,
  955  |       data: JSON.stringify({
  956  |         p_session_id: sessionId, p_sub_id: subId,
  957  |         p_ip: '10.0.0.7', p_user_agent: 'PW/4.7',
  958  |       }),
  959  |     })).json();
  960  |     expect(lv.ok).toBe(true);
  961  | 
  962  |     // invalid session rejected
  963  |     const bad = await (await ctx.post(`${DB}/rpc/client_log_view`, { headers: HC,
  964  |       data: JSON.stringify({ p_session_id: 'ses-nonexistent', p_sub_id: subId }),
  965  |     })).json();
  966  |     expect(bad).toEqual({ ok: false, error: 'invalid_session' });
  967  | 
  968  |     // ── 3. client_set_response → 'response_submit' audit row, prev/new captured
  969  |     const resp = await (await ctx.post(`${DB}/rpc/client_set_response`, { headers: HC,
  970  |       data: JSON.stringify({
  971  |         p_session_id: sessionId, p_sub_id: subId,
  972  |         p_status: 'approved_with_changes', p_comment: 'small text tweaks please',
  973  |       }),
  974  |     })).json();
  975  |     expect(resp.ok).toBe(true);
  976  | 
  977  |     // ── 4. Supervisor sees all three actions, ordered DESC
  978  |     const rows = await (await ctx.post(`${DB}/rpc/admin_list_audit`, { headers: HC,
  979  |       data: JSON.stringify({
  980  |         p_supervisor_id: 'harish', p_limit: 100, p_client_user_id: cuId, p_action: null,
  981  |       }),
  982  |     })).json();
  983  |     const actions = rows.map(r => r.action);
  984  |     expect(actions).toContain('login');
  985  |     expect(actions).toContain('recce_view');
  986  |     expect(actions).toContain('response_submit');
  987  | 
  988  |     const respRow = rows.find(r => r.action === 'response_submit');
  989  |     expect(respRow.sub_id).toBe(subId);
  990  |     expect(respRow.detail.new_status).toBe('approved_with_changes');
  991  |     expect(respRow.detail.has_comment).toBe(true);
  992  |     expect(respRow.client_user_email).toBe(cuEmail);
  993  | 
  994  |     // ── 5. action filter
  995  |     const onlyLogins = await (await ctx.post(`${DB}/rpc/admin_list_audit`, { headers: HC,
  996  |       data: JSON.stringify({
  997  |         p_supervisor_id: 'harish', p_limit: 100, p_client_user_id: cuId, p_action: 'login',
  998  |       }),
  999  |     })).json();
  1000 |     expect(onlyLogins.length).toBeGreaterThanOrEqual(1);
  1001 |     expect(onlyLogins.every(r => r.action === 'login')).toBe(true);
  1002 | 
  1003 |     // ── 6. non-supervisor → empty (gate)
  1004 |     const denied = await (await ctx.post(`${DB}/rpc/admin_list_audit`, { headers: HC,
  1005 |       data: JSON.stringify({ p_supervisor_id: 'mukesh', p_limit: 100 }),
  1006 |     })).json();
  1007 |     expect(Array.isArray(denied)).toBe(true);
  1008 |     expect(denied).toHaveLength(0);
  1009 | 
  1010 |     // Cleanup
  1011 |     const HCd = { headers: { ...HC, Prefer: 'return=minimal' } };
  1012 |     const HRd = { headers: { ...HR, Prefer: 'return=minimal' } };
  1013 |     await ctx.delete(`${DB}/submissions?sub_id=eq.${subId}`, HRd);
  1014 |     await ctx.delete(`${DB}/notify_queue?payload->>sub_id=eq.${subId}`, HCd);
  1015 |     await ctx.delete(`${DB}/notify_queue?recipient_email=eq.${cuEmail}`, HCd);
  1016 |     await ctx.delete(`${DB}/mail_outbox?to_email=eq.${cuEmail}`, HCd);
  1017 |     await ctx.delete(`${DB}/client_audit_log?client_user_id=eq.${cuId}`, HCd);
  1018 |     await ctx.delete(`${DB}/client_session?client_user_id=eq.${cuId}`, HCd);
  1019 |     await ctx.delete(`${DB}/client_invite?invite_id=eq.${inviteId}`, HCd);
  1020 |     await ctx.delete(`${DB}/client_user?client_user_id=eq.${cuId}`, HCd);
  1021 |     await ctx.delete(`${DB}/client?client_id=eq.${clientId}`, HCd);
  1022 |     await ctx.delete(`${DB}/counter?counter_id=eq.${counterId}`, HCd);
  1023 |     await ctx.dispose();
  1024 |   });
  1025 | 
  1026 |   test('Phase 4.8 — sessions: list_my_sessions / revoke_my_session / revoke_all_other_sessions / admin_list_sessions / admin_revoke_session', async () => {
  1027 |     const ctx = await request.newContext();
  1028 |     const HC = { 'Accept-Profile': 'counters', 'Content-Profile': 'counters', 'Content-Type': 'application/json' };
  1029 |     const HC_PMIN = { ...HC, Prefer: 'return=minimal' };
  1030 |     const stamp     = Date.now().toString(36).slice(-6);
  1031 |     const clientId  = `cli-p48-${stamp}`;
  1032 |     const cuEmail   = `p48-${stamp}@spec.test`;
  1033 | 
  1034 |     // Seed client + invited user, then create three sessions via three invites
  1035 |     await ctx.post(`${DB}/client`, { headers: HC_PMIN, data: JSON.stringify({
```