---
name: real-agent-preval
description: "Single-address pre-valuation pitch pack. One full UK address in, 5-page A4 PDF out (cover · subject valuation · market context · comparables · recently with <brand>). Consumes the real-agent-property-data MCP — no MCP tools of its own. EPC certificate fields (total_floor_area_m2, current_energy_rating, lodgement_date) are pasted by the operator into inputs.json before invocation."
skills:
  - skills/property-preval/SKILL.md
hooks:
  PreToolUse:
    - matcher: "Write|Edit|MultiEdit"
      command: "${CLAUDE_PLUGIN_ROOT}/hooks/preval-prompt-required.sh"
always: false
metadata: {"platform":{"optional":true,"embed":["admin"]}}
---

# Real Agent — Preval

Consumer sub-plugin. No MCP server, no new tools — only a skill (`property-preval`) that takes one full UK address plus operator-supplied brand tokens, subject details, agent listings, and a market summary, and renders a **5-page A4 pre-valuation PDF** designed as a sales pitch for the listing.

## What it produces

A 5-page A4 PDF and the source HTML, written to `~/Documents/Real Agent/preval/<postcode-compact>-<YYYY-MM-DD>/`:

- **Page 1 — Cover.** Full-bleed subject hero photo with gradient scrim. Light brand wordmark top-left. Address in display-italic. Postcode chip. Four-up meta strip (Report · Address · Postcode · Generated). Lifted from the `property-market-report` cover contract.
- **Page 2 — Subject valuation.** KPI strip (floor area, bedrooms, EPC rating, type). Valuation panel: headline range = `derived sqft × sold £/sqft 70pc band` (Land Registry), asking £/sqft cross-check, operator adjustments (`subject.adjustments[]`) shown as a stacked list with colour-coded percentages, final indicative range pill. Floor area is derived from `subject.total_floor_area_m2` (operator-pasted from the EPC certificate) — a null value aborts the run with `epc-certificate-not-supplied`.
- **Page 3 — Market context.** Market summary headline + paragraphs with drop cap. KPI strip (avg asking £, avg sold £, £/sqft). Price-growth panel (YoY) + demand pill with gauge. 7-year sparkline of £ and £/sqft. Same patterns as `property-market-report`.
- **Page 4 — Comparables.** Full-width Land Registry sold-transactions table (≤ 6 rows), stacked above a full-width live-asking-comparables tile grid (≤ 4 tiles). Never side-by-side — corrects the cramped two-column layout in v1 preval.
- **Page 5 — Recently with `<brand>` + sources.** Operator-curated `agent_listings[]` rendered as a clickable tile grid with status badges (Sold / Under offer / For sale), then the sources & methodology block. The vendor reads this page and knows who to call.

## Tool dependencies

The skill fans out to **12** PropertyData MCP calls in parallel (postcode-keyed): `prices`, `prices-per-sqf`, `sold-prices`, `sold-prices-per-sqf`, `growth`, `growth-psf`, `demand`, `demand-rent`, `property-types`, `crime`, `flood-risk`, `council-tax`.

`property-data-address-match-uprn` and `property-data-planning-applications` are deliberately not called (CRM hygiene and dev-precedent reports, respectively).

The three EPC certificate fields the page-2 KPI strip needs — `total_floor_area_m2`, `current_energy_rating`, `lodgement_date` — are pasted by the operator into `subject` in `inputs.json` before invocation. There is no MCP fan-out for EPC; the PreToolUse hook and `render.py` both abort with `epc-certificate-not-supplied` if any of the three fields is null.

## Failure handling

Every failure is fail-loud. The skill emits `[preval] aborted reason=<cause> …` and exits 2; no partial `index.html` or PDF is left on disk.

- **PropertyData `key-not-registered`** → abort `reason=property-data-key-not-registered` with the `property-data-key-register` remediation hint.
- **PropertyData `http-429`** → back off and retry the single throttled tool once. A second `http-429` aborts `reason=property-data-rate-limited`.
- **PropertyData `http-5xx` / network failure** → abort `reason=property-data-unavailable`.
- **Any of the 12 PropertyData log lines missing** within 60s of `[preval] start` → abort `reason=observability-missing tool=<name>`. A silent tool drop must never proceed to render.
- **Subject EPC certificate field missing** — any of `subject.total_floor_area_m2`, `subject.current_energy_rating`, `subject.lodgement_date` is null → abort `reason=epc-certificate-not-supplied`. The operator pastes all three from the EPC certificate into `inputs.json` before re-invoking. There is no mid-run prompt and no MCP fallback.
- See `skills/property-preval/SKILL.md` § Hard breakpoints for the full table of abort causes.

## External dependencies

- Requires `real-agent-property-data` enabled on the account with a registered PropertyData API key (`property-data-key-register`).
- Requires the operator to paste the three EPC certificate fields (`total_floor_area_m2`, `current_energy_rating`, `lodgement_date`) into `subject` in `inputs.json` before invocation. There is no automated EPC lookup.
- Requires Google Chrome at `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome` for headless `--print-to-pdf`. Same Chrome dependency as `property-market-report`.

## Hooks

- `hooks/preval-prompt-required.sh` — PreToolUse gate on `Write|Edit|MultiEdit` of `**/preval/**/inputs.json`. Blocks (exit 2) before the file lands on disk if any of `epc-certificate-not-supplied`, `agent-listings-invented`, `market-summary-invented`, or `brand-invented` applies. The same five causes (plus `cover-hero-not-subject`) are re-checked by `render.py`'s `_assert_inputs` gate — defence in depth against silent fallback completions. Paths outside `preval/inputs.json` pass through.
