# UCM6301 Recording Resolver Dry Run

## Scope

This phase resolves recording metadata without changing VTiger. It does not update `recordingurl`, construct a playable URL, call `/recapi`, or download audio.

The inspected ordinary inbound queue calls proved this correlation:

```text
vtiger_pbxmanager.sourceuuid == HTTPS API sub-CDR uniqueid
```

This is not claimed as universal behavior for transfers, outbound calls, or other untested call topologies.

## Components

- `ami/lib/UcmHttpsApiClient.php` implements the authenticated JSON `POST /api` flow.
- `ami/lib/UcmRecordingResolver.php` correlates a finalized PBXManager row to recording metadata.
- `tools/ucm_recording_sync.php` reads finalized inbound rows and prints sanitized dry-run results.
- `ami/config/ucm_https_api.secret.php` is the ignored runtime configuration; create it from the tracked sample.

The listener is not changed and the validated standalone probe remains independent.

Authenticated requests retry authentication at most once, and only for documented API status `-6` (a required cookie is missing). Permission, parameter, unsafe-command, no-data, and other semantic API errors are not retried.

## Resolution rules

The VTiger-to-UCM time offset is not globally established. The initial resolver therefore derives the calendar date from VTiger `starttime` and queries the complete date rather than treating a narrow VTiger timestamp window as authoritative. Query pagination has configured record and page limits. A complete, structurally and path-validated date result is cached in memory for the current process, keyed by the exact calendar date and effective record/page limits. Errors, incomplete pagination, and unsafe data are not cached. Row correlation and `getRecordInfosByCall` confirmation still run independently.

For each CDR tree the resolver dynamically examines `main_cdr` and every `sub_cdr_N`. It requires:

1. exactly one tree containing a node whose complete `uniqueid` equals `sourceuuid`;
2. a compatible caller number in that tree;
3. exactly one recording-bearing node in that tree whose `uniqueid` also equals `sourceuuid`;
4. a valid `AcctId` from that same node;
5. exact normalized equality between the node's `recordfiles` and `getRecordInfosByCall`.

Caller values are reduced to digits. Full equality is preferred; otherwise suffix equality is accepted only when both normalized values contain at least seven digits. Caller matching validates an exact identifier match and never replaces it.

Recording values support comma and `@` delimiters, whitespace, empty entries, and trailing `@`. Only relative `.wav` paths are accepted. Parent traversal, null bytes, backslashes, leading slashes, URL schemes, query strings, and fragments are rejected.

## Dry-run usage

Create the ignored runtime configuration without copying credentials into tracked files:

```bash
cp ami/config/ucm_https_api.secret.php.sample ami/config/ucm_https_api.secret.php
chmod 600 ami/config/ucm_https_api.secret.php
```

Then populate it manually and run either a date or one PBXManager ID:

```bash
php tools/ucm_recording_sync.php --date=2026-07-20 --limit=10
php tools/ucm_recording_sync.php --pbxmanager-id=13490
```

The tool selects only finalized inbound rows whose `recordingurl` is null or empty. It performs prepared read-only queries, processes rows independently, masks caller numbers and identifiers, and never writes to the database. Its final counters report authentications, bounded reauthentications, date fetches/cache hits, and recording-metadata confirmations without exposing API content.

## Explicit outcomes

The resolver distinguishes resolved metadata from no matching tree, multiple trees, caller mismatch, no recording node, multiple recording nodes, unsafe paths, metadata mismatch, and API/network failure. The CLI maps those details to its limited sanitized output vocabulary.

## Known exclusions

- transfers and channel replacement;
- trees with multiple recording-bearing nodes;
- outbound calls;
- browser playback and authenticated proxy design;
- construction or storage of `recordingurl`;
- automatic scheduling;
- audio access or download.

## Validation

```bash
php tests/UcmRecordingResolverTest.php
php tests/UcmHttpsApiClientTest.php
php -l ami/lib/UcmHttpsApiClient.php
php -l ami/lib/UcmRecordingResolver.php
php -l tools/ucm_recording_sync.php
php -l ami/config/ucm_https_api.secret.php.sample
git diff --check
git status --short
```
