---
phase: 01-analyze-pipeline
fixed_at: 2026-05-20T00:00:00Z
review_path: .planning/phases/01-analyze-pipeline/01-REVIEW.md
iteration: 1
findings_in_scope: 10
fixed: 10
skipped: 0
status: all_fixed
---

# Phase 01: Code Review Fix Report

**Fixed at:** 2026-05-20
**Source review:** .planning/phases/01-analyze-pipeline/01-REVIEW.md
**Iteration:** 1

**Summary:**
- Findings in scope: 10
- Fixed: 10
- Skipped: 0

## Fixed Issues

### CR-01: Uint8Array RangeError for files of 12-15 bytes

**Files modified:** `src/drive.ts`
**Commit:** eaca6b9
**Applied fix:** Used the defensive clamp form from the review: `const viewLen = Math.min(16, buffer.byteLength)` so the view never exceeds the actual buffer size. Guard threshold stays at `< 12` (all probes read at most index 11), ensuring buffers of 12-15 bytes are sniffed correctly rather than throwing RangeError.

### WR-01: Empty-value hidden inputs silently dropped in interstitial parser

**Files modified:** `src/drive.ts`
**Commit:** eaca6b9
**Applied fix:** Changed the value regex from `/value="([^"]+)"/i` (requires ≥1 char) to `/value="([^"]*)"/i` (allows empty string). Empty sentinel inputs from Drive's virus-scan confirmation form are now correctly forwarded as query parameters.

### WR-02: Relative form action URL throws uncaught TypeError

**Files modified:** `src/drive.ts`
**Commit:** eaca6b9
**Applied fix:** Wrapped `new URL(decodeEntities(actionMatch[1]))` in a try/catch. On failure (relative path), resolves against `https://drive.usercontent.google.com` as the base. The variable is declared `let url: URL` before the try block so it remains in scope for the subsequent hidden-input loop.

### WR-03: Polled file state cast without validation causes misleading 504

**Files modified:** `src/gemini.ts`
**Commit:** eaca6b9
**Applied fix:** Changed `(await response.json()) as UploadedFile` to cast through `Partial<UploadedFile>` first, then added a `typeof polled.state !== 'string'` guard that throws `GeminiError(..., 502)` immediately rather than silently looping to timeout exhaustion.

### WR-04: Status region has no aria-live — dynamic changes invisible to screen readers

**Files modified:** `web/src/App.tsx`, `web/src/styles.css`
**Commit:** eaca6b9
**Applied fix:** Wrapped the loading/error paragraphs in a persistent `<div aria-live="polite" aria-atomic="true" className="status-region">` that is always in the DOM from initial render. Added `.status-region:empty { display: none }` to styles.css so the empty wrapper takes no visual space when no message is active.

### WR-05: Raw JS engine parse error message embedded in GeminiError reaches wrangler tail logs

**Files modified:** `src/gemini.ts`
**Commit:** eaca6b9
**Applied fix:** Replaced the interpolated error message with a static string `'Gemini response was not valid JSON'`. The raw text is already logged at 500-char truncation in the `console.warn` call above; the engine's parse error message added no useful information and circumvented the guard. Added `void parseErr` to explicitly acknowledge the caught value.

### IN-01: Dead CSS adjacent-sibling selector

**Files modified:** `web/src/styles.css`
**Commit:** eaca6b9
**Applied fix:** Dropped the dead `.section-heading + .section-heading-wrap` rule (the `+` combinator never matched because `.section-heading` is a child of a wrapper div, not a sibling). Replaced with `.section-heading-wrap { margin-top: var(--space-6) }` applied directly to the wrapper element, which is the only placement used in App.tsx.

### IN-02: `lang="uk"` (Ukrainian) declared on an English-language page

**Files modified:** `web/index.html`
**Commit:** eaca6b9
**Applied fix:** Changed `<html lang="uk">` to `<html lang="en">`. All visible application text is in English.

### IN-03: `z.string().url()` accepts non-Drive URL schemes as valid input

**Files modified:** `src/schema.ts`
**Commit:** eaca6b9
**Applied fix:** Added a `.refine()` after `.url()` that parses the URL and checks `hostname === 'drive.google.com' || hostname === 'drive.usercontent.google.com'`. Returns a user-facing message `'URL must be a Google Drive share link.'` on failure. The try/catch inside the refiner handles the edge case where `new URL()` itself throws (already caught by `.url()`, but belt-and-suspenders).

### IN-04: ESLint and Prettier absent despite being listed as day-one conventions

**Files modified:** `CLAUDE.md`
**Commit:** eaca6b9
**Applied fix:** Updated the Conventions section in CLAUDE.md (previously empty) to document all active coding conventions and explicitly note that ESLint + Prettier are deferred out of scope for the 2026-05-22 time-budget delivery. No deps or scripts added — that is out of scope per task instructions.

---

_Fixed: 2026-05-20_
_Fixer: Claude (gsd-code-fixer)_
_Iteration: 1_
