---
phase: 13-ai-field-placement-and-pre-fill
plan: 01
subsystem: ai
tags: [openai, pdfjs-dist, coordinate-conversion, tdd, gpt-4o-mini, structured-output]

# Dependency graph
requires:
  - phase: 12.1-per-field-text-editing-and-quick-fill
    provides: textFillData keyed by field UUID, DocumentPageClient state architecture
  - phase: 10-expanded-field-types-end-to-end
    provides: SignatureFieldType union, SignatureFieldData interface
provides:
  - extractPdfText(filePath) — pdfjs-dist server-side text extraction returning PageText[]
  - aiCoordsToPagePdfSpace() — AI top-left pct to PDF bottom-left points with Y-axis flip
  - classifyFieldsWithAI() — GPT-4o-mini structured output call returning SignatureFieldData[] + textFillData
  - AiFieldCoords interface
  - Unit test for coordinate conversion (3 cases, US Letter dimensions)
affects: [13-02-ai-route, 13-03-ui-button, 13-04-integration-test]

# Tech tracking
tech-stack:
  added: [openai@6.32.0]
  patterns:
    - pdfjs-dist legacy build with GlobalWorkerOptions.workerSrc='' for Node.js server-side use
    - Manual json_schema response_format with strict=true (NOT zodResponseFormat — broken with Zod v4)
    - Standard field sizes override AI dimensions (checkbox=24x24pt, others=144x36pt)
    - textFillData keyed by crypto.randomUUID() field ID (not label)

key-files:
  created:
    - teressa-copeland-homes/src/lib/ai/extract-text.ts
    - teressa-copeland-homes/src/lib/ai/field-placement.ts
    - teressa-copeland-homes/src/lib/pdf/__tests__/ai-coords.test.ts
  modified:
    - teressa-copeland-homes/package.json (openai dependency added)
    - teressa-copeland-homes/package-lock.json

key-decisions:
  - "openai 6.32.0 installed as production dependency (not devDependency)"
  - "GlobalWorkerOptions.workerSrc = '' required for Node.js server-side pdfjs-dist — do NOT share with browser components"
  - "Manual json_schema response_format confirmed required — zodResponseFormat broken with Zod v4 (issues #1540 #1602 #1709)"
  - "Standard field sizes (checkbox=24x24, others=144x36pt) override AI widthPct/heightPct for consistency"
  - "textFillData keyed by UUID assigned in route handler — not by label — matches Phase 12.1 design"

patterns-established:
  - "Pattern: lib/ai/* files carry // server-only guard comment — never imported from client components"
  - "Pattern: aiCoordsToPagePdfSpace is the single named utility for AI-to-PDF coord conversion — replicated from FieldPlacer.tsx formula"

requirements-completed: [AI-01, AI-02]

# Metrics
duration: 2min
completed: 2026-03-21
---

# Phase 13 Plan 01: AI Field Placement Foundation Summary

**openai SDK installed, pdfjs-dist server-side text extraction module, and GPT-4o-mini structured output field classifier with Y-axis-flip coordinate conversion verified by TDD unit tests**

## Performance

- **Duration:** 2 min
- **Started:** 2026-03-21T22:58:46Z
- **Completed:** 2026-03-21T23:01:00Z
- **Tasks:** 2 (TDD: RED then GREEN)
- **Files modified:** 5

## Accomplishments

- TDD RED phase: wrote 3 failing unit tests for aiCoordsToPagePdfSpace with US Letter (612x792pt) dimensions
- TDD GREEN phase: implemented extract-text.ts and field-placement.ts passing all 3 tests
- openai 6.32.0 installed as production dependency
- TypeScript compiles without errors (npx tsc --noEmit passes)

## Task Commits

Each task was committed atomically:

1. **Task 1: Write failing unit test for aiCoordsToPagePdfSpace** - `f7d74c0` (test)
2. **Task 2: Implement extract-text.ts and field-placement.ts (GREEN)** - `c1e1e5e` (feat)

## Files Created/Modified

- `teressa-copeland-homes/src/lib/ai/extract-text.ts` - extractPdfText() using pdfjs-dist legacy build; GlobalWorkerOptions.workerSrc='' for Node.js; PageText interface; text capped at 2000 chars/page
- `teressa-copeland-homes/src/lib/ai/field-placement.ts` - AiFieldCoords interface; aiCoordsToPagePdfSpace() with Y-axis flip; classifyFieldsWithAI() calling GPT-4o-mini with manual json_schema; standard field sizes; textFillData keyed by UUID
- `teressa-copeland-homes/src/lib/pdf/__tests__/ai-coords.test.ts` - 3 unit tests: text field near top, checkbox near bottom-right, client-sig at center
- `teressa-copeland-homes/package.json` - openai 6.32.0 added to dependencies

## Decisions Made

- Manual json_schema response_format confirmed (NOT zodResponseFormat) — broken with Zod v4.3.6 per issues #1540, #1602, #1709; this is a locked decision from STATE.md research phase
- Standard field sizes override AI-returned widthPct/heightPct: checkbox=24x24pt, all others=144x36pt — consistent with FieldPlacer defaults, prevents poorly-sized AI fields
- textFillData built with UUID keys assigned in route handler — matches Phase 12.1 design where DocumentPageClient uses field.id as the key
- GlobalWorkerOptions.workerSrc='' set at module level in extract-text.ts — this is the Node.js fake-worker pattern; client components (PdfViewer, PreviewModal) set their own workerSrc independently

## Deviations from Plan

None - plan executed exactly as written.

## Issues Encountered

None.

## User Setup Required

**OPENAI_API_KEY must be set in .env.local** before the AI auto-place feature works. The classifyFieldsWithAI() function throws `'OPENAI_API_KEY not configured'` if the key is absent — this is a clear error that surfaces to the agent in the browser. No silent failures.

No other external service configuration required for this plan.

## Next Phase Readiness

- Both AI utility modules exist and are importable from the server-only route handler (Plan 02)
- Coordinate conversion is unit-tested and correct for US Letter dimensions
- openai SDK ready for use in `/api/documents/[id]/ai-prepare` route (Plan 02)
- FieldPlacer + DocumentPageClient unchanged — Plan 03 will add the UI button and state wiring
- Blocker from STATE.md still active: AI coordinate accuracy on real Utah forms is untested — Plan 04 integration test required before Phase 13 ships to production

---
*Phase: 13-ai-field-placement-and-pre-fill*
*Completed: 2026-03-21*
