# NanoLLM UDS Client + Peer-Cred Check + Pre-Send Validation

**Task**: AZ-673_vlm_client_nanollm_ipc
**Name**: Unix-domain socket client to NanoLLM + peer-cred check + ROI pre-send validation
**Description**: Maintain the Unix-domain-socket connection to the NanoLLM process. Perform a peer-credential check on connect (where supported). Validate ROI payload (size, format) BEFORE sending across the IPC channel. No network egress — UDS only.
**Complexity**: 5 points
**Dependencies**: AZ-640_initial_structure, AZ-672_vlm_client_provider_trait
**Component**: vlm_client
**Tracker**: AZ-673
**Epic**: AZ-631

## Problem

VLM runs as a local NanoLLM/VILA1.5-3B process. The link is a Unix-domain socket — no network egress, ever. The connection MUST be peer-credential-checked on connect (Linux `SO_PEERCRED`) to confirm the peer process belongs to the expected user / GID; failure is a hard error requiring operator intervention, not a silent retry. ROI payloads MUST be validated for size + format BEFORE crossing the socket — never spend network IPC time on a payload that's known-too-big.

## Outcome

- `NanoLlmClient::connect(socket_path) -> Result<Self, ConnectError>` opens a UDS connection and performs `SO_PEERCRED` check; mismatch returns `Err(PeerCredMismatch)`.
- `NanoLlmClient::assess(roi_crop, prompt) -> VlmAssessment` validates the ROI pre-send and sends a single request; awaits one response within ≤5 s; returns `VlmAssessment`.
- Bounded reconnect on transport loss; on peer-cred failure NO reconnect happens (operator intervention required).
- Health surface: `vlm_latency_p50/p99`, `errors_by_kind`, `peer_cred_check_pass_rate`.

## Scope

### Included
- UDS client (`tokio::net::UnixStream`).
- `SO_PEERCRED` check (Linux; on macOS dev hosts, log a warning and proceed for development purposes only — production target is Jetson Linux).
- Pre-send size + format validation.
- Reconnect state machine (bounded).
- Bounded request deadline.

### Excluded
- VlmAssessment schema validation (task 35).
- Provider trait wiring (task 33).

## Acceptance Criteria

**AC-1: Happy path against fixture NanoLLM**
Given a fixture NanoLLM process listening on a UDS path with correct peer-cred
When `connect` is called and then `assess(roi, "is this concealed?")` is called
Then `connect` returns Ok; `assess` returns `VlmAssessment { status: Ok, label, confidence, .. }` within ≤5 s.

**AC-2: Peer-cred mismatch hard-fails connect**
Given a fixture peer with wrong UID
When `connect` is called
Then it returns `Err(PeerCredMismatch)`; subsequent connect attempts are blocked until config-driven intervention (no automatic retry); health → red.

**AC-3: Oversize ROI rejected pre-send**
Given an ROI larger than `max_roi_bytes`
When `assess(...)` is called
Then it returns `VlmAssessment { status: SchemaInvalid, .. }` synchronously without writing to the socket.

**AC-4: Response timeout returns explicit status**
Given a fixture NanoLLM that never responds within 5 s
When `assess(...)` is called
Then it returns `VlmAssessment { status: Timeout, .. }` after ≤5 s; subsequent requests are not blocked.

## Non-Functional Requirements

**Performance**
- Per-ROI latency: ≤5 s p99 (per `description.md §8`).

**Reliability**
- No network egress (hard rule — UDS only).
- Peer-cred mismatch never silently retried.

## Runtime Completeness

- **Named capability**: NanoLLM/VILA1.5-3B IPC over UDS + peer-cred enforcement.
- **Production code that must exist**: real UDS connection; real `SO_PEERCRED`; real pre-send validation.
- **Allowed external stubs**: a Python NanoLLM stub script in tests that echoes a canned response.
- **Unacceptable substitutes**: TCP to localhost instead of UDS is unacceptable (violates the no-network-egress rule).
