# VlmAssessment Schema Validation + Model-Version Tracking

**Task**: AZ-674_vlm_client_schema_and_model_version
**Name**: VlmAssessment schema validation + model_version tracking + status enum coverage
**Description**: Validate every NanoLLM response against the `VlmAssessment` schema. On schema-invalid, return `status: schema_invalid` + log the raw response (size-capped) for offline analysis. Capture `model_version` on every assessment for forensic correlation; log on change.
**Complexity**: 3 points
**Dependencies**: AZ-640_initial_structure, AZ-673_vlm_client_nanollm_ipc
**Component**: vlm_client
**Tracker**: AZ-674
**Epic**: AZ-631

## Problem

The NanoLLM process emits free-form text, but the autopilot consumes ONLY a validated structured `VlmAssessment`. Schema-invalid responses MUST not propagate as malformed evidence — they're returned as `status: schema_invalid` with the raw response logged size-capped for offline analysis. Model-version capture supports forensic correlation when an assessment's quality is later disputed.

## Outcome

- `VlmAssessmentParser::parse(raw_response) -> VlmAssessment` validates the response against the schema; on failure returns `VlmAssessment { status: SchemaInvalid, .. }` and logs the raw response (size-capped to e.g. 4 KB) at warn level.
- `model_version` field is populated on every assessment from the NanoLLM-reported version; changes are logged at info level once per change.
- Status enum exhaustively covers `Ok | Inconclusive | Timeout | SchemaInvalid | IpcError | Disabled`; consumer match-exhaustion is enforced by the type.

## Scope

### Included
- Schema definition in `shared/contracts/vlm-assessment.json` (or equivalent Rust schema).
- Parser implementation.
- Model-version change detection.
- Size-capped raw-response logging.

### Excluded
- The UDS transport (task 34).
- Provider trait wiring (task 33).

## Acceptance Criteria

**AC-1: Valid response parses successfully**
Given a fixture NanoLLM response with all required fields
When `parse(raw)` runs
Then it returns `VlmAssessment { status: Ok, label, confidence, model_version, .. }`.

**AC-2: Schema-invalid response returns schema_invalid + logs**
Given a fixture response missing a required field
When `parse(raw)` runs
Then it returns `VlmAssessment { status: SchemaInvalid, .. }` and the raw response excerpt (size-capped) is observable in log output.

**AC-3: Model version change logged once**
Given an assessment with `model_version = "v1.0"` followed by another with `model_version = "v1.1"`
When the change is detected
Then a single log entry observes the change; subsequent assessments with `v1.1` do NOT re-log.

**AC-4: Status enum is exhaustive**
Given consumer code that matches on `VlmAssessment.status`
When a new variant is added (compile-time)
Then the compiler forces handling of the new variant; no `_ => …` catch-all in the policy code-path.

## Non-Functional Requirements

**Performance**
- Schema validation: ≤2 ms.

**Reliability**
- Schema mismatches never silent.

## Contract

- Canonical typed model: `data_model.md §VlmAssessment`. Schema lives at `shared/contracts/vlm-assessment.json`.

## Runtime Completeness

- **Named capability**: VlmAssessment schema validation + model-version awareness.
- **Production code that must exist**: real schema validator; real model-version tracker.
- **Unacceptable substitutes**: silently mapping a schema-invalid response to `status: Ok` with placeholder fields is unacceptable.
