diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md
index 280f8d5..b027011 100644
--- a/.planning/ROADMAP.md
+++ b/.planning/ROADMAP.md
@@ -274,7 +274,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 →
| 6. Signing Flow | v1.0 | 6/6 | Complete | 2026-03-21 |
| 7. Audit Trail and Download | v1.0 | 3/3 | Complete | 2026-03-21 |
| 8. Schema Foundation and Signing Page Safety | 2/2 | Complete | 2026-03-21 | - |
-| 9. Client Property Address | 1/1 | Complete | 2026-03-21 | - |
+| 9. Client Property Address | 1/1 | Complete | 2026-03-21 | - |
| 10. Expanded Field Types End-to-End | v1.1 | 0/3 | Not started | - |
| 11. Agent Saved Signature and Signing Workflow | v1.1 | 0/3 | Not started | - |
| 12. Filled Document Preview | v1.1 | 0/2 | Not started | - |
diff --git a/.planning/STATE.md b/.planning/STATE.md
index aa96812..61dfd3d 100644
--- a/.planning/STATE.md
+++ b/.planning/STATE.md
@@ -3,7 +3,7 @@ gsd_state_version: 1.0
milestone: v1.1
milestone_name: Smart Document Preparation
status: unknown
-last_updated: "2026-03-21T18:21:41.741Z"
+last_updated: "2026-03-21T18:32:35.250Z"
progress:
total_phases: 9
completed_phases: 9
diff --git a/.planning/phases/09-client-property-address/09-VERIFICATION.md b/.planning/phases/09-client-property-address/09-VERIFICATION.md
new file mode 100644
index 0000000..ef79d1c
--- /dev/null
+++ b/.planning/phases/09-client-property-address/09-VERIFICATION.md
@@ -0,0 +1,154 @@
+---
+phase: 09-client-property-address
+verified: 2026-03-21T00:00:00Z
+status: human_needed
+score: 5/5 must-haves verified
+re_verification: false
+human_verification:
+ - test: "Create client with property address and verify profile display"
+ expected: "ClientModal shows Property Address field; after save, the address appears in the header card on the client profile page"
+ why_human: "Visual rendering and form submission flow cannot be verified programmatically"
+ - test: "Edit client with pre-filled address"
+ expected: "Clicking Edit on a client with an address opens ClientModal with the address pre-filled in the Property Address field"
+ why_human: "defaultPropertyAddress prop hydration requires interactive browser session"
+ - test: "Client with no address shows no address line"
+ expected: "Client profile header card has no empty address row or placeholder text when propertyAddress is null"
+ why_human: "Conditional render of {client.propertyAddress && ...} requires visual confirmation"
+ - test: "PreparePanel text fill pre-seed"
+ expected: "Opening a document for a client with an address shows a pre-populated 'propertyAddress' row in the text fill section without agent input"
+ why_human: "Initial state seeding from lazy useState initializer requires runtime verification"
+ - test: "PreparePanel empty for client without address"
+ expected: "Text fill section shows a single blank row (no pre-populated rows) for a client without a property address"
+ why_human: "Runtime state initialization branch cannot be confirmed from static analysis"
+ - test: "Empty address coerced to NULL"
+ expected: "Saving a client with a blank Property Address field stores NULL (not empty string) in the database"
+ why_human: "DB write coercion via || null requires database-level inspection or server log review"
+---
+
+# Phase 9: Client Property Address Verification Report
+
+**Phase Goal:** Agent can store a property address on a client profile so it is available as structured data for AI pre-fill
+**Verified:** 2026-03-21
+**Status:** human_needed
+**Re-verification:** No — initial verification
+
+---
+
+## Goal Achievement
+
+### Observable Truths
+
+| # | Truth | Status | Evidence |
+|---|-------|--------|----------|
+| 1 | Agent can add or edit a property address on any client profile from the portal (create and edit modes in ClientModal) | VERIFIED | `ClientModal.tsx` line 13: `defaultPropertyAddress?: string` in props; line 62-73: full input field with `name="propertyAddress"`, `defaultValue={defaultPropertyAddress}`, placeholder "123 Main St, Salt Lake City, UT 84101". Both create and edit modes use the same form action. |
+| 2 | Property address is persisted to the database as NULL when left blank, not as empty string | VERIFIED | `clients.ts` line 38: `propertyAddress: parsed.data.propertyAddress \|\| null` in createClient; line 67: same pattern in updateClient `.set()`. Empty string from FormData coerces to NULL before DB write. |
+| 3 | Property address is displayed on the client profile page when non-null | VERIFIED | `ClientProfileClient.tsx` lines 51-53: `{client.propertyAddress && (
{client.propertyAddress}
)}` — conditional render present. Server page `clients/[id]/page.tsx` uses `db.select()` wildcard which includes all columns, so `propertyAddress` flows to the component. |
+| 4 | When opening a prepared document for a client who has a property address, the PreparePanel's text fill area arrives pre-populated with the address under the key 'propertyAddress' | VERIFIED | Three-layer wiring confirmed: (a) `documents/[docId]/page.tsx` line 23 selects `propertyAddress: clients.propertyAddress`; (b) line 68 passes `clientPropertyAddress={docClient?.propertyAddress ?? null}` to `PreparePanel`; (c) `PreparePanel.tsx` line 31-33 lazy useState: `() => (clientPropertyAddress ? { propertyAddress: clientPropertyAddress } : {})` seeds state; (d) line 156 passes `initialData` to `TextFillForm`; (e) `TextFillForm.tsx` line 20: `useState(() => buildInitialRows(initialData))` renders pre-seeded rows. The seeded `textFillData` is included in the POST body at `PreparePanel.tsx` line 110. |
+| 5 | Clients without a property address work identically to before — no regressions on existing data | VERIFIED | Schema column is purely nullable (no `.notNull()`, no `.default()`). Zod schema uses `.optional()`. `|| null` coercion only applies to empty string. `clientPropertyAddress ?? null` in page.tsx handles missing docClient. Lazy initializer falls back to `{}` when null. No changes to unrelated server actions or API routes. |
+
+**Score:** 5/5 truths verified (automated checks pass; human runtime verification required for UI/UX behaviors)
+
+---
+
+### Required Artifacts
+
+| Artifact | Provides | Status | Details |
+|----------|----------|--------|---------|
+| `src/lib/db/schema.ts` | nullable `propertyAddress` column on clients table | VERIFIED | Line 58: `propertyAddress: text("property_address")` — no `.notNull()`, no `.default()` — matches nullable pattern of `sentAt`/`filePath` |
+| `drizzle/0007_equal_nekra.sql` | ALTER TABLE migration for property_address | VERIFIED | File exists; content: `ALTER TABLE "clients" ADD COLUMN "property_address" text;` — single clean statement. Registered as `"tag": "0007_equal_nekra"` in `meta/_journal.json`. Snapshot `0007_snapshot.json` exists. Note: filename differs from plan spec (`0007_property_address.sql`) — drizzle-kit auto-generates names; this is expected behavior. |
+| `src/lib/actions/clients.ts` | createClient/updateClient extended with propertyAddress | VERIFIED | Zod schema line 13: `propertyAddress: z.string().optional()`. createClient line 38: `propertyAddress: parsed.data.propertyAddress \|\| null`. updateClient line 67: same coercion in `.set({...})`. |
+| `src/app/portal/_components/ClientModal.tsx` | Property address input field in create/edit modal | VERIFIED | Lines 13, 16: prop declared and destructured. Lines 62-73: labeled input field with correct `name="propertyAddress"`, `defaultValue={defaultPropertyAddress}`, no `required` attribute. |
+| `src/app/portal/_components/ClientProfileClient.tsx` | Property address display in profile card | VERIFIED | Line 23: `propertyAddress?: string \| null` in Props type. Lines 51-53: conditional render. Line 95: `defaultPropertyAddress={client.propertyAddress ?? undefined}` passed to edit modal. |
+| `src/app/portal/(protected)/documents/[docId]/page.tsx` | propertyAddress in client select, passed to PreparePanel | VERIFIED | Line 23: `propertyAddress: clients.propertyAddress` in `.select()`. Line 68: `clientPropertyAddress={docClient?.propertyAddress ?? null}` prop on PreparePanel. |
+| `src/app/portal/(protected)/documents/[docId]/_components/PreparePanel.tsx` | clientPropertyAddress prop accepted, seeds textFillData + initialData | VERIFIED | Line 13: prop in interface. Lines 31-33: lazy useState with propertyAddress key. Lines 154-157: ``. Line 110: `textFillData` included in POST body. |
+| `src/app/portal/(protected)/documents/[docId]/_components/TextFillForm.tsx` | initialData prop + buildInitialRows helper for pre-seeded rows | VERIFIED (unplanned addition) | Lines 8-9: `initialData?: Record` prop. Lines 11-17: `buildInitialRows()` helper converts record to rows, appends blank row. Line 20: lazy useState uses helper. Not in PLAN artifacts — added as deviation fix during Task 3 checkpoint. Functionally necessary. |
+
+---
+
+### Key Link Verification
+
+| From | To | Via | Status | Details |
+|------|----|-----|--------|---------|
+| `src/lib/db/schema.ts` | `drizzle/0007_equal_nekra.sql` | drizzle-kit generate + migrate | WIRED | Column `text("property_address")` in schema; migration `ALTER TABLE "clients" ADD COLUMN "property_address" text` in file; journal entry `0007_equal_nekra` confirmed. |
+| `documents/[docId]/page.tsx` | `PreparePanel.tsx` | `clientPropertyAddress` prop | WIRED | page.tsx line 68: `clientPropertyAddress={docClient?.propertyAddress ?? null}` — matches plan's expected pattern `clientPropertyAddress={.*propertyAddress`. PreparePanel interface declares the prop; lazy useState consumes it. |
+| `ClientProfileClient.tsx` | `ClientModal.tsx` | `defaultPropertyAddress` prop on edit modal call | WIRED | `ClientProfileClient.tsx` line 95: `defaultPropertyAddress={client.propertyAddress ?? undefined}` — matches plan's expected pattern `defaultPropertyAddress={client\.propertyAddress`. ClientModal declares and uses the prop. |
+| `PreparePanel.tsx` | `TextFillForm.tsx` | `initialData` prop | WIRED (deviation) | PreparePanel lines 154-157 pass `initialData` to TextFillForm. TextFillForm's `buildInitialRows()` converts to TextRow[] with blank row appended. This link was not in the PLAN's key_links but is the critical bridge that makes pre-seeding visible in the UI. |
+| `PreparePanel.tsx` | `/api/documents/[docId]/prepare` | `textFillData` in POST body | WIRED | Line 110: `body: JSON.stringify({ textFillData, emailAddresses })`. The `textFillData` state is seeded with `{ propertyAddress: "..." }` on mount — this value reaches the API route. |
+
+---
+
+### Requirements Coverage
+
+| Requirement | Source Plan | Description | Status | Evidence |
+|-------------|-------------|-------------|--------|----------|
+| CLIENT-04 | 09-01-PLAN.md | Agent can add a property address to a client profile | SATISFIED | ClientModal input field (create + edit), updateClient/createClient server actions with NULL coercion, DB column with migration. Full CRUD path verified. |
+| CLIENT-05 | 09-01-PLAN.md | Client property address is available as a pre-fill data source alongside client name | SATISFIED | propertyAddress selected in document page query, passed through to PreparePanel as clientPropertyAddress, lazy-initialized into textFillData state as `{ propertyAddress: "..." }`, included in prepare POST body, rendered as pre-seeded row via TextFillForm.initialData. |
+
+**No orphaned requirements.** REQUIREMENTS.md traceability table maps CLIENT-04 and CLIENT-05 to Phase 9 only. Both are accounted for in the plan.
+
+---
+
+### Anti-Patterns Found
+
+| File | Line | Pattern | Severity | Impact |
+|------|------|---------|----------|--------|
+| — | — | — | — | None found |
+
+Note: grep for `TODO/FIXME/XXX/HACK/placeholder` in modified files returned only HTML `placeholder=` input attributes (legitimate UI copy, not stubs). No empty implementations, no stub return values, no console.log-only handlers found.
+
+---
+
+### Human Verification Required
+
+All 6 automated truth checks pass. The following require browser/runtime confirmation:
+
+#### 1. Create Client with Property Address
+
+**Test:** Navigate to /portal/clients, click "Add Client". Confirm the modal shows a "Property Address" field below the Email field. Create a test client with address "456 Oak Ave, Provo, UT 84601". Save and open the client profile.
+**Expected:** Property address appears in the client header card below the email address.
+**Why human:** Visual rendering and form submit flow.
+
+#### 2. Edit Client Pre-fill
+
+**Test:** Click "Edit" on a client that has a property address.
+**Expected:** ClientModal opens with the Property Address field pre-filled with the existing address. Changing and saving updates the profile.
+**Why human:** `defaultValue` hydration and round-trip persistence.
+
+#### 3. No Address Client — No Empty Line
+
+**Test:** View the profile of a client with no property address.
+**Expected:** Header card shows name and email only. No empty line, no "undefined", no placeholder text.
+**Why human:** Conditional render `{client.propertyAddress && ...}` requires visual confirmation.
+
+#### 4. PreparePanel Pre-seed Visible
+
+**Test:** Open the prepare/document page for a document assigned to a client with a property address.
+**Expected:** The text fill section shows a row pre-populated with label "propertyAddress" and the client's address value, plus a blank row below it.
+**Why human:** Lazy useState initializer behavior and TextFillForm row rendering requires runtime check.
+
+#### 5. PreparePanel Empty for No-Address Client
+
+**Test:** Open the prepare page for a document assigned to a client with no property address.
+**Expected:** Text fill section shows a single blank row (the default state), identical to pre-Phase 9 behavior.
+**Why human:** Fallback branch `() => {}` initialization requires runtime check.
+
+#### 6. NULL Coercion Confirmed
+
+**Test:** Create or edit a client, leave the Property Address field blank, save. Inspect the database record or confirm no empty-string side effects (e.g., address row does not appear on profile).
+**Expected:** Profile shows no address line (confirming null, not empty string, was stored).
+**Why human:** Database-level NULL vs. empty string requires server/DB inspection or behavioral inference from the profile display.
+
+---
+
+### Gaps Summary
+
+No automated gaps found. All five observable truths are fully verified at all three levels (exists, substantive, wired). Both requirement IDs (CLIENT-04, CLIENT-05) are satisfied with complete implementation evidence.
+
+One notable unplanned artifact was added during the phase: `TextFillForm.tsx` received an `initialData` prop and `buildInitialRows()` helper as a deviation fix identified at the human verification checkpoint. This addition is correctly implemented and is the critical link that makes the pre-seed feature visible to the user.
+
+The phase is blocked only on human runtime verification of UI rendering and form behavior.
+
+---
+
+_Verified: 2026-03-21_
+_Verifier: Claude (gsd-verifier)_