collabSupport/services/voiceDiag/VOICE_PATH_ATTRIBUTION.md
jmcqueen 90a56c4640 Fix Prisma overlay tunnel discovery with site-scoped query_params.
Use topology/links and anynetlinks filters with eq/in operators so
store WAN follow-ups return real peer tunnels instead of unscoped dumps.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-28 09:01:40 -04:00

64 lines
3.2 KiB
Markdown

# Prisma Phase 2 — Voice Path Attribution Discovery
Time-boxed discovery notes for "voice is on this tunnel" / per-handset
attribution. Phase 1 (runtime waninterface status, overlay tunnels,
app DPI by `path_type`) ships without these.
## Confirmed Phase 1 surfaces (pan.dev + code)
| Need | Endpoint | Notes |
|------|----------|-------|
| Circuit runtime status | `GET /sdwan/v2.1/api/sites/{siteId}/waninterfaces/{wiId}/status` | Wired in `getWanInterfaceStatus` |
| Overlay tunnels | `POST /sdwan/v2.0/api/topology/links/query` with `query_params.{source\|target}_site_id.{in\|eq}` | Preferred — includes status, peer names, vpnlinks[] |
| Anynet fallback | `POST /sdwan/v4.0/api/anynetlinks/query` with `query_params.ep{1\|2}_site_id.{eq\|in}` | Config rows; no runtime status |
| Voice DPI by path_type | `getAppMetric` with `filter.path_type=[VPN]` etc. | AppPerf* only; AppAudioMos omits path_type |
| Alarm → tunnel id | `info.vpn_reasons[].vpn_link_id` | `extractVpnLinkIdsFromAlarmInfo` |
## Live-tenant corrections (2026-07-28 / store 1005)
| Issue | Fix |
|-------|-----|
| `limit: { count: N }` → 400 "expected int" | Topology/anynet `limit` is a bare int |
| `query: { site_id: [...] }` silently ignored | Use `query_params: { field: { eq\|in: … } }` (array under query_params → 400) |
| 100 tunnels all `peer — unknown` | Site-scoped topology query; resolve peer opposite local site; renderer collapses all-unknown |
| `vpnlinks` have no site fields | Prefer topology links; anynet via ep1/ep2; never unscoped vpnlinks dump |
| Pairing down volume | Prefer public-anynet; rank down/unknown first; cap ≤12; renderer shows ≤6 |
| Cascading 429s | Path-type breakout gated by `PRISMA_VOICE_PATH_TYPE_BREAKOUT`; status GETs capped |
Probe recipes:
```bash
node scripts/prismaProbe.js wi-status <siteId> <wanInterfaceId>
node scripts/prismaProbe.js tunnels <siteId>
node scripts/prismaProbe.js app-by-path-type <siteId> <appId> --metric loss
node scripts/prismaProbe.js try-shapes app-by-path <siteId> <appId> <wiId>
```
## Phase 2a candidates (probe before implementing further)
1. **App metrics + `filter.path`** (waninterface id) — already supported in
`getAppMetric({ pathIds })` behind `PRISMA_VOICE_PATH_ATTRIBUTION=1`.
Confirm live tenant accepts the filter (SCHEMA_CHECK_FAIL risk).
2. **Flow / session / app-path details** — SCM UI "Application Path Details"
HAR may reveal monitor endpoints that bind RTP to a specific path.
Candidates: topology query v3.6, object_stats, app/wan contexts.
3. **Join keys to Webex** — need client IP, subnet, or device id in Prisma
flow records to map to Meraki/Webex handset inventory. **Not confirmed.**
## Phase 2c status
`attributeVoicePathToEndpoint()` in
`services/callReport/voicePathAttribution.js` returns `null` until a
join key is confirmed. Path-level / path_type-level annotation is live
via `annotateWanWithPath()`.
## Confidence language
| Level | Meaning |
|-------|---------|
| `site` | Site-wide DPI only (`siteLevelApprox: true`) |
| `path_type` | One path_type uniquely worse in window |
| `path` | One waninterface uniquely worse (`byPath`) |
| `endpoint` | Per-handset — **not available** without flow join keys |