# GHL Social Planner — LinkedIn Image Ops (lessons 2026-08-11)

Constraints verified live while fixing the Pipeline Layer week-of-2026-08-10 batch. Applies to any GHL Social Planner work touching LinkedIn post media.

## 1. Published LinkedIn posts: text editable, image LOCKED

LinkedIn does not allow changing the image on a published post — only the text. Once published, the only fix for a wrong image is delete + repost (loses engagement). Verify images BEFORE publish; retrofitting new cards onto already-published posts is impossible (six `old-*` cards built for the 08-03 week were dead on arrival).

## 2. Map posts by CONTENT, never by date label or list order

When PUTting media updates across several posts, an ID→date map from an earlier listing went stale and cross-attached Tue/Thu images. The verify re-list caught it. Procedure: GET each post, read the `summary` opening line, match the image to THAT text. Never assume list order = date order; never reuse an ID→date mapping across turns.

## 3. GHL list API quirk: `platform` field lies

Posts bound to the LinkedIn account (`..._profile` account ID in `accountIds`) can list as `platform: "google"`. Display quirk only — routing follows the account ID. A post with this label published to LinkedIn correctly. Don't "fix" routing based on the label.

## 4. Batch .md / draft files may not reflect what actually got scheduled

A schedule-time text swap (2026-08-13) was never written back to the vault batch file, so the vault showed intent, not reality. When debugging "wrong content" reports, treat the GHL post list as ground truth and draft files as intent. After any schedule-time swap, write the replacement back to the batch file.

## 5. Editorial card render system (Pipeline Layer vault)

`vault/LinkedIn Posting System/visual-assets/generate_card.py` renders the FIG.-series cards (navy, corner brackets, duotone headshot right). Fully parameterized via `build_card(fig_label, tag, eyebrow_white, eyebrow_orange, headline_lines, caption, out_path, photo_path)`. Headshots on disk: `rob-headshot.png`, `rob-headshot-tight-crop.jpg`.

**Headline width limit:** BigShoulders-Bold 88px starting at x=64 overflows into the photo zone (~x≥578) past ~560px measured width — keep headline lines ≤ ~15 chars and measure with `F_HEADLINE.getlength()` before rendering. Eyebrow text (20px) can be much longer safely.

**vision_analyze over-reports text/photo overlap** on these cards (false positives on "PICK THE TOOL" and on headline-vs-face). Confirm overlap claims with a pixel check (orange mask, count pixels with x>578) before re-rendering, and phrase the question as "does text touch the FACE" not "the photo".
