Problem
After a simple call between two internal extensions ends, the client checks whether an AI summary is ready via HEAD /summary/:uniqueid?linkedid=... (nethcti-middleware). This succeeds for the extension that placed the call, but returns 403 for the extension that received it.
Root cause
Confirmed on a test instance for a real 201→202 call (call CDR: uniqueid=linkedid=1783509165.120, src=201, dst=202, ANSWERED):
andrea (201, caller): HEAD /summary/1783509165.120?linkedid=1783509165.120 -> 204
antonio (202, callee): HEAD /summary/1783509165.124?linkedid=1783509165.120 -> 403
The caller and callee report the uniqueid of their own Asterisk channel leg (confirmed in phone-island/astproxy: uniqueid is per-channel, linkedid is shared for the call). For a simple two-party call, CDR only ever stores one row, keyed by the originating (caller's) channel uniqueid — the callee's own uniqueid (1783509165.124 here) never appears in CDR at all.
resolveAuthorizedUniqueIDFull (methods/transcription.go) has an early "skip NO ANSWER" check that queries CDR by the raw client-supplied uniqueid and rejects if no matching answered row is found — it can't distinguish "row exists but wasn't answered" from "no row exists for this id at all", so the callee's leg is always rejected before ever trying the linkedid-based fallback that exists specifically to resolve this case. The same ambiguity also breaks the external-party cross-check used a few steps later (an empty "no CDR row" result is treated as a real technical row with zero external parties, instead of "unknown, don't filter on it").
Test Case
- Place a call between two internal extensions with transcription/summaries enabled.
- After hangup, check
HEAD /summary/:uniqueid?linkedid=... from both extensions' sessions.
- The caller's request succeeds; the callee's returns
403, even though both are the same call and the callee is a legitimate participant.
Problem
After a simple call between two internal extensions ends, the client checks whether an AI summary is ready via
HEAD /summary/:uniqueid?linkedid=...(nethcti-middleware). This succeeds for the extension that placed the call, but returns403for the extension that received it.Root cause
Confirmed on a test instance for a real 201→202 call (call CDR:
uniqueid=linkedid=1783509165.120,src=201,dst=202,ANSWERED):The caller and callee report the
uniqueidof their own Asterisk channel leg (confirmed in phone-island/astproxy:uniqueidis per-channel,linkedidis shared for the call). For a simple two-party call, CDR only ever stores one row, keyed by the originating (caller's) channel uniqueid — the callee's own uniqueid (1783509165.124here) never appears in CDR at all.resolveAuthorizedUniqueIDFull(methods/transcription.go) has an early "skip NO ANSWER" check that queries CDR by the raw client-supplieduniqueidand rejects if no matching answered row is found — it can't distinguish "row exists but wasn't answered" from "no row exists for this id at all", so the callee's leg is always rejected before ever trying thelinkedid-based fallback that exists specifically to resolve this case. The same ambiguity also breaks the external-party cross-check used a few steps later (an empty "no CDR row" result is treated as a real technical row with zero external parties, instead of "unknown, don't filter on it").Test Case
HEAD /summary/:uniqueid?linkedid=...from both extensions' sessions.403, even though both are the same call and the callee is a legitimate participant.