diff --git a/clients/viewer/src/components/pipeline-viewer/StageTabs.tsx b/clients/viewer/src/components/pipeline-viewer/StageTabs.tsx
index d2bf4dc..baf50e5 100644
--- a/clients/viewer/src/components/pipeline-viewer/StageTabs.tsx
+++ b/clients/viewer/src/components/pipeline-viewer/StageTabs.tsx
@@ -141,7 +141,7 @@ function isProcessingInStage(
extraction: ['Docling Extraction', 'OCR Re-extraction', 'Extraction'],
analysis: ['PDF Classification', 'Structure Analysis'],
headings: ['Heading Levels', 'Heading Reconciliation'],
- translation: ['Page Content Corrections', 'Code Block Languages'],
+ translation: ['Page Content Corrections', 'Code Block Languages', 'Form Fields'],
assembly: ['Cross-Page Fixes', 'Final Cleanup'],
};
const names = nameMap[stage.name];
diff --git a/clients/viewer/src/types/pipeline-viewer.ts b/clients/viewer/src/types/pipeline-viewer.ts
index e539880..eda1baf 100644
--- a/clients/viewer/src/types/pipeline-viewer.ts
+++ b/clients/viewer/src/types/pipeline-viewer.ts
@@ -45,7 +45,7 @@ export const PIPELINE_STAGES: StageDefinition[] = [
{ name: 'extraction', label: 'Extraction', steps: ['docling', 'docling_ocr'] },
{ name: 'analysis', label: 'Analysis', steps: ['classification', 'structure'] },
{ name: 'headings', label: 'Headings', steps: ['heading_levels', 'heading_reconciliation'] },
- { name: 'translation', label: 'Translation', steps: ['page_content', 'code_blocks'] },
+ { name: 'translation', label: 'Translation', steps: ['page_content', 'code_blocks', 'form_fields'] },
{ name: 'assembly', label: 'Assembly', steps: ['boundaries', 'cleanup'] },
];
diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml
index b01e80a..6f226f8 100644
--- a/docker-compose.dev.yml
+++ b/docker-compose.dev.yml
@@ -108,8 +108,9 @@ services:
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-test}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-test}
- AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN:-}
- # Clear AWS_PROFILE to prevent boto3 from looking for profile config in container
- - AWS_PROFILE=
+ # AWS_PROFILE is intentionally NOT set here. boto3 treats a set-but-empty
+ # AWS_PROFILE as a missing named profile (ProfileNotFound) and ignores the
+ # exported env creds above. Leaving it unset makes boto3 use those creds.
- AWS_DEFAULT_REGION=us-east-1
# Disable AWS Instance Metadata Service (IMDS) to prevent boto3 hang in Docker
- AWS_EC2_METADATA_DISABLED=true
diff --git a/docs/reference/pipeline-phases.md b/docs/reference/pipeline-phases.md
index 2db405f..cc03d22 100644
--- a/docs/reference/pipeline-phases.md
+++ b/docs/reference/pipeline-phases.md
@@ -10,16 +10,16 @@ The pipeline has **5 versioned conversion phases** plus a **PII Review** gate th
|---|---|---|---|
| **PII Review** (gate) | `pii_scan` | No | Runs Presidio against a text-only docling pass before full extraction. If findings exist, the streaming pipeline blocks on `session.pii_decision_event` until the user approves or denies via `POST /api/v1/pipeline/sessions/{sid}/pii-decision`. Denial aborts the pipeline. Can be opted out with `skip_pii_scan=true`. |
| 1. **Extraction** | `docling`, `docling_ocr` (conditional) | No | PDF → markdown + page images via IBM Docling. `docling_ocr` only fires when the classifier flags a scanned document. |
-| 2. **Analysis** | `classification`, `structure` | Yes | `classification` tags the document as digital / scanned / malformed. `structure` identifies headings, footnotes, code blocks, per-page layout attributes. |
+| 2. **Analysis** | `classification`, `structure` | Yes | `classification` tags the document as digital / scanned / malformed. `structure` identifies headings, footnotes, code blocks, per-page layout attributes, and per-page content flags (`has_tables`, `has_lists`, `has_forms`, …) that gate Translation work. |
| 3. **Headings** | `heading_reconciliation`, `heading_levels` | Yes | `heading_reconciliation` reconciles per-page heading candidates against the global outline. `heading_levels` normalises the hierarchy (H1 → H2 → H3, no skips). |
-| 4. **Translation** | `page_content`, `code_blocks` | Yes | `page_content` does per-page accessibility corrections (invokes image / table / list subagents). `code_blocks` tags fenced blocks with detected programming language. |
+| 4. **Translation** | `page_content`, `code_blocks`, `form_fields` | Yes | `page_content` does per-page accessibility corrections (invokes image / table / list subagents). `code_blocks` tags fenced blocks with detected programming language. `form_fields` runs on every form page (structure `has_forms` or a deterministic underline/checkbox scan) and converts detected fields into accessible HTML (`