# Cron Job: Lobby Tracker — reintentar Veo/audio y agregar 5 políticos

**Job ID:** 89188738f73a
**Run Time:** 2026-05-03 06:33:59
**Schedule:** once in 3h

## Prompt

[IMPORTANT: The user has invoked the "lobbytracker-updater" skill, indicating they want you to follow its instructions. The full skill content is loaded below.]

---
name: lobbytracker-updater
description: Use when running or maintaining the weekly Lobby Tracker Argentina source-update agent. Iterates politicians, researches new public developments, inserts sourced connections via Supabase Management API, and updates totals without inventing data.
version: 1.0.0
author: Pipo / Hermes Agent
license: MIT
metadata:
  hermes:
    tags: [lobbytracker, supabase, cron, research, argentina, politics]
    related_skills: [hermes-agent, systematic-debugging]
---

# Lobby Tracker Argentina — Weekly Source Update Agent

## Overview

Lobby Tracker Argentina is a Next.js 14 app at `https://lobbytracker.vercel.app` tracking public political connections between Argentine politicians and Israel lobby groups. The weekly updater's job is conservative: find only new, public, source-backed developments and insert them into Supabase with evidence.

**Non-negotiable rule:** never invent data. If a connection cannot be supported by a public source excerpt, do not insert it.

## Project constants

- Source: `/home/ubuntu/lobbytracker`
- Live site: `https://lobbytracker.vercel.app`
- Supabase project ref: `xvrlnhwbvyyydnnzctbk`
- Supabase URL: `https://xvrlnhwbvyyydnnzctbk.supabase.co`
- Supabase anon key: `sb_publishable_zi-E4qkqGxVRRt9Ym8-Rrw_Iq_g2WAP`
- Management API endpoint: `https://api.supabase.com/v1/projects/xvrlnhwbvyyydnnzctbk/database/query`
- Required env vars: `SUPABASE_ACCESS_TOKEN`, `VERCEL_TOKEN`
- Deploy command: `cd /home/ubuntu/lobbytracker && vercel --prod --yes`

## Schema

```sql
politicians (id, name, position, jurisdiction, party, image_url, total_lobby_ars, total_lobby_usd, status, qr_url, bio)
lobby_groups (id, name, acronym, description, website)
connections (id, politician_id, lobby_group_id, connection_type, amount_ars, amount_usd, date, description)
evidence (id, connection_id, source_url, source_name, evidence_type, excerpt)
```

RLS is public read-only. Writes must go through the Supabase Management API using `SUPABASE_ACCESS_TOKEN`, or through the Supabase pooler if explicitly needed.

## Weekly cron schedule

Recommended schedule: every Sunday morning Argentina time.

```cron
0 9 * * 0
```

Cron prompt should load this skill and use toolsets: `web`, `terminal`, `delegation`, optionally `file`.

## High-level workflow

1. Verify the live site responds with HTTP 200.
2. Fetch all politicians from Supabase REST.
3. Fetch existing lobby groups, connections, and evidence.
4. Spawn one `delegate_task` subagent per politician in parallel.
5. Each subagent researches new public legal/news/procurement developments.
6. Parent agent compares candidate findings against existing DB rows.
7. Insert only genuinely new, source-backed connections.
8. Insert an evidence row for every new connection.
9. Recompute and update politician totals.
10. Produce a concise run report: checked politicians, candidates found, inserted rows, skipped duplicates, sources used, errors.

## Prerequisite checks

Run before any weekly update:

```bash
curl -sS -o /tmp/lobbytracker_home.html -w '%{http_code}\n' https://lobbytracker.vercel.app

test -n "$SUPABASE_ACCESS_TOKEN" && echo ok-supabase-token

curl -sS 'https://xvrlnhwbvyyydnnzctbk.supabase.co/rest/v1/politicians?select=id,name,position,jurisdiction,party,total_lobby_ars,total_lobby_usd,status' \
  -H 'apikey: sb_publishable_zi-E4qkqGxVRRt9Ym8-Rrw_Iq_g2WAP' \
  -H 'Authorization: Bearer sb_publishable_zi-E4qkqGxVRRt9Ym8-Rrw_Iq_g2WAP'
```

If the site is not 200, do not insert data until the outage is understood. If REST reads fail, do not continue.

## Source research instructions for subagents

Each politician subagent must return structured findings only; it should not write to the DB itself unless the parent explicitly delegates DB writes. Use the subagent for evidence gathering and duplicate analysis, then centralize writes in the parent to avoid races.

Subagent context template:

```text
You are researching Lobby Tracker Argentina updates for politician: <name> (<position>, <jurisdiction>, party <party>).

Goal: find NEW public developments involving Israel lobby groups, public contracts, security/defense firms, trips to Israel, appointments, court/legal developments, procurement records, official bulletins, or credible journalism.

Existing DB connections for this politician:
<compact JSON of existing connections and evidence URLs>

Rules:
- Do not invent data.
- Use web_search and web_extract.
- Prefer primary sources: Boletín Oficial, BAC/Compr.ar, official city/national procurement portals, court rulings, official press releases.
- Credible journalism can support context, but contract/legal claims need primary sources when possible.
- Return only candidates with source_url, source_name, excerpt, date, connection_type, lobby_group_name/acronym, description, amount_ars, amount_usd.
- If no new source-backed finding exists, return an empty candidate list and say what queries were tried.
- Do not insert into Supabase.
```

Recommended searches per politician:

```text
"<politician name>" Israel contrato
"<politician name>" israelí seguridad contrato
"<politician name>" Cámara de Comercio Argentino Israelí
"<politician name>" Mario Montoto
"<politician name>" Danaide CoDeSur seguridad
"<politician name>" viaje Israel
"<politician name>" Boletín Oficial Israel
"<politician name>" compras contratación seguridad Israel
site:boletinoficial.gob.ar "<politician name>" Israel
site:buenosairescompras.gob.ar "<politician name>" Israel
site:comprar.gob.ar "<politician name>" Israel
```

## Duplicate detection

Treat a candidate as duplicate if any of these match an existing connection/evidence:

- Same politician + same lobby group + same date + materially same description.
- Same source URL already exists in `evidence` for that politician.
- Same procurement/contract identifier, even if description wording differs.
- Same appointment/trip/legal event already represented by another source.

If uncertain, skip and report as `needs_manual_review`; do not insert.

## SQL write pattern via Management API

Use one transaction per new connection. Always insert connection + evidence together.

```bash
python3 - <<'PY'
import json, os, subprocess, textwrap
sql = r"""
begin;
-- example only: replace values with validated candidate data
insert into connections
  (politician_id, lobby_group_id, connection_type, amount_ars, amount_usd, date, description)
values
  ('<politician_uuid>', '<lobby_group_uuid>', '<type>', <amount_ars_or_null>, <amount_usd_or_null>, '<YYYY-MM-DD>'::date, '<description>')
returning id;
commit;
"""
print(json.dumps({"query": sql}))
PY
```

The actual call:

```bash
curl -sS -X POST 'https://api.supabase.com/v1/projects/xvrlnhwbvyyydnnzctbk/database/query' \
  -H "Authorization: Bearer $SUPABASE_ACCESS_TOKEN" \
  -H 'Content-Type: application/json' \
  --data-binary @payload.json
```

For safer multi-row operations, generate JSON with Python, not hand-escaped shell strings.

### Full transaction template

```sql
begin;

with new_connection as (
  insert into connections
    (politician_id, lobby_group_id, connection_type, amount_ars, amount_usd, date, description)
  values
    ('<politician_uuid>', '<lobby_group_uuid>', '<connection_type>', <amount_ars_or_null>, <amount_usd_or_null>, '<YYYY-MM-DD>'::date, '<description>')
  returning id
)
insert into evidence
  (connection_id, source_url, source_name, evidence_type, excerpt)
select
  id,
  '<source_url>',
  '<source_name>',
  '<evidence_type>',
  '<verbatim_or_tight_excerpt>'
from new_connection;

update politicians p
set
  total_lobby_ars = coalesce((select sum(coalesce(amount_ars, 0)) from connections c where c.politician_id = p.id), 0),
  total_lobby_usd = coalesce((select sum(coalesce(amount_usd, 0)) from connections c where c.politician_id = p.id), 0)
where p.id = '<politician_uuid>';

commit;
```

Date values must use `::date` casting. For unknown amounts, use SQL `null`, not `0`, unless the source explicitly says zero.

## Lobby group handling

Before inserting a connection, match `lobby_group_name/acronym` against existing `lobby_groups`.

- If exact or obvious match exists, reuse the ID.
- If no match exists, insert a new `lobby_groups` row in the same transaction before inserting `connections`.
- New lobby group descriptions must be factual and source-backed; if only a name is known, keep description minimal.

## Amount normalization

- Store amounts in `amount_ars` and/or `amount_usd` only when the source states an amount or when a transparent source conversion is documented in the evidence/report.
- Do not convert currencies silently.
- For contracts in ARS with historical values, keep nominal ARS in source date currency.
- If a source gives USD but not ARS, set ARS null; and vice versa.

## Pooler fallback

Oracle Cloud often cannot reach direct Supabase IPv6 hosts. If using raw Postgres instead of Management API, use Supabase pooler:

- Host: `aws-0-sa-east-1.pooler.supabase.com`
- Port: `6543`
- Region: `sa-east-1`

Prefer Management API unless there is a specific reason to use the pooler.

## Verification after writes

After every insertion batch:

```bash
curl -sS 'https://xvrlnhwbvyyydnnzctbk.supabase.co/rest/v1/connections?select=id,politician_id,connection_type,date,description,evidence(source_url,source_name,excerpt)&order=date.desc&limit=20' \
  -H 'apikey: sb_publishable_zi-E4qkqGxVRRt9Ym8-Rrw_Iq_g2WAP' \
  -H 'Authorization: Bearer sb_publishable_zi-E4qkqGxVRRt9Ym8-Rrw_Iq_g2WAP'
```

Verify:

- Every new connection has at least one evidence row.
- Evidence has `source_url`, `source_name`, and `excerpt`.
- Totals changed only for affected politicians.
- Live site still returns HTTP 200.

## Common pitfalls

1. **Supabase `.then().catch()` in frontend build.** Supabase query objects can be `PromiseLike<void>` and TypeScript may reject `.catch()`. Use `async/await` with `try/catch` in app code.
2. **Direct DB IPv6 unreachable from Oracle Cloud.** Use Management API or pooler host `aws-0-sa-east-1.pooler.supabase.com:6543`.
3. **Raw SQL date type errors.** Cast dates as `'<YYYY-MM-DD>'::date`.
4. **RLS blocks writes through public anon REST.** Writes require Management API with `SUPABASE_ACCESS_TOKEN`.
5. **Weak source quality.** Social media screenshots and unsourced claims are not enough for DB inserts.
6. **Duplicate claims from syndicated articles.** Prefer one primary source evidence row, not multiple duplicate media copies.
7. **Autonomous overreach.** If a candidate is politically plausible but not documented, skip it.

## Cron run final report format

```markdown
## Lobby Tracker weekly update — YYYY-MM-DD

- Site health: 200 / problem
- Politicians checked: N
- Subagents run: N
- New candidates found: N
- Inserted connections: N
- Skipped duplicates: N
- Needs manual review: N

### Inserted
- <politician>: <connection_type>, <date>, <lobby_group>, <amount if any> — <source_url>

### Manual review
- <politician>: <reason> — <source_url>

### No new findings
- <politician>: queries tried, no source-backed change
```

## Verification checklist

- [ ] Live site returns HTTP 200 before and after the run.
- [ ] Politicians fetched from Supabase REST.
- [ ] Existing connections/evidence fetched before research.
- [ ] One subagent spawned per politician.
- [ ] Every candidate has source URL, source name, excerpt, date, and type.
- [ ] Duplicates skipped.
- [ ] Every inserted connection has an evidence row in the same transaction.
- [ ] `total_lobby_ars` and `total_lobby_usd` recalculated for affected politicians.
- [ ] Final report delivered to Chicho.

[IMPORTANT: The user has invoked the "political-tracker-card" skill, indicating they want you to follow its instructions. The full skill content is loaded below.]

---
name: political-tracker-card
description: Generate political tracker/scorecard red cards (AIPAC Tracker style) using GPT Image 2 or Nano Banana via OpenRouter. Magazine-cover aesthetic, dark red backgrounds, silhouettes, large dollar amounts, editorial typography. For social media political graphics exposing lobby connections, campaign financing, and public contracts.
triggers:
  - "political tracker"
  - "tracker card"
  - "red card"
  - "AIPAC Tracker style"
  - "lobby card"
  - "political scorecard"
  - "generate political graphic"
  - "lobby tracker graphic"
  - "image generation"
  - "GPT Image 2"
  - "Nano Banana"
  - "political infographic card"
requirements:
  env_vars:
    - OPENROUTER_API_KEY
  system_packages:
    - curl
    - python3
---

# Political Tracker Card Generation

Generate red/green political tracker cards in AIPAC Tracker style using AI image generation APIs via OpenRouter.

## Models Available

| Model | OpenRouter ID | Best For | Quality |
|---|---|---|---|
| **GPT Image 2** (preferred) | `openai/gpt-5.4-image-2` | Editorial, photorealistic, magazine covers, text-heavy layouts | Best |
| Nano Banana Pro | `google/gemini-3-pro-image-preview` | Complex layouts, 2K/4K, identity preservation | Excellent |
| Nano Banana 2 | `google/gemini-3.1-flash-image-preview` | Fast iteration, drafts | Very Good |
| Nano Banana (v1) | `google/gemini-2.5-flash-image` | Quick edits, basic cards | Good |

**Default: GPT Image 2** — photorealistic, best text rendering, magazine-cover quality.

## Prompting Best Practices (from OpenAI docs)

1. **Structure**: artifact type → background/scene → subject → layout → text in quotes → constraints
2. **Text**: put exact text in double quotes, specify role (HEADLINE, SUBHEAD, LABEL, FOOTER)
3. **Quality**: use `"high"` for text-heavy cards
4. **Constraints**: "no watermark, no cartoon, no extra text, no border"
5. **For photorealism**: use words like "photorealistic", "editorial photography", "magazine cover", "Sports Illustrated style"

## Template: Red Card Generation Script

```bash
OPENROUTER_KEY=$(grep OPENROUTER_API_KEY ~/.hermes/.env | cut -d= -f2)

curl -s --max-time 300 "https://openrouter.ai/api/v1/chat/completions" \
  -H "Authorization: Bearer $OPENROUTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-5.4-image-2",
    "modalities": ["image", "text"],
    "image_config": {"aspect_ratio": "1:1", "image_size": "1K"},
    "messages": [{
      "role": "user",
      "content": "Sports magazine cover style political tracker card. Photorealistic, glossy editorial photography, dramatic ESPN Magazine / Sports Illustrated aesthetic. Dark crimson red background with volumetric smoke, cinematic god rays, high-contrast. Left: grayscale silhouette with rim lighting. Right: giant glossy white dollar amount. HEADLINE: [NAME]. SUBHEAD: [POSITION]. NUMBER: [AMOUNT]. LABEL: [LOBBY NAME] TOTAL. Bottom: magazine cover lines with stats. Barcode, date stamp. Photorealistic editorial magazine cover."
    }]
  }' -o /tmp/card.json

python3 -c "
import json, base64
with open('/tmp/card.json') as f:
    d = json.load(f)
msg = d.get('choices',[{}])[0].get('message',{})
imgs = msg.get('images',[])
if imgs:
    url = imgs[0]['image_url']['url']
    data = url.split(',')[1]
    with open('/tmp/tracker_card.png','wb') as f:
        f.write(base64.b64decode(data))
    print('Saved: /tmp/tracker_card.png')
else:
    print(f'Error: {json.dumps(d.get(\"error\",{}), indent=2)[:300]}')
"
```

## Fallback: Nano Banana 2

```bash
# Same curl structure, different model:
"model": "google/gemini-3.1-flash-image-preview"
# Prompts should be shorter, less text-heavy
```

## AIPAC Tracker Design Spec

**Red cards** (exposing pro-lobby politicians):
- Grayscale candidate photo/silhouette on LEFT (45%)
- Dark crimson/smoky red background filling ENTIRE card
- GIANT white dollar amount on RIGHT (55%) — the "glowing number"
- Label: "[LOBBY NAME] TOTAL" in uppercase
- Bullet points with specific funding sources
- Footer: "TRACKER — [COUNTRY] 🇦🇷"

**Green cards** (endorsed/clean candidates):
- Same layout but green background
- Shows $0 or minimal lobby funding
- "REJECTS [LOBBY] CASH" label

## GPT Image 2 Sports Magazine Villain Style (May 2026)

For maximum visual impact, use the sports signing poster aesthetic (Lautaro Martinez Inter Milan style). GPT Image 2 excels here. Key elements:

- **HIGH ANGLE** perspective — camera above, looking down (they're beneath us)
- **ELECTRIC RED LIGHTNING** bolts across dark crimson background
- **VILLAIN ENERGY** — grayscale silhouette, red rim lighting, no eye contact, caught-in-the-act
- **SPORTS POSTER TYPOGRAPHY** — massive bold names, glossy white stat numbers
- **4:5 vertical** aspect ratio (best for Twitter/Instagram)
- **Glossy magazine texture**, cinematic god rays, volumetric fog

Prompt template:
```
Sports magazine cover political tracker card, 4:5 vertical.
HIGH ANGLE looking DOWN — ominous villain energy.
Deep blood-red background with ELECTRIC RED LIGHTNING,
cinematic fog, glossy magazine texture.
Silhouette of suited politician, grayscale, high angle, red rim-lit.
Bold white sports fonts. Top: "LOBBY TRACKER ARGENTINA 🇦🇷"
Massive: "[LAST NAME]". Above: "[FIRST NAME]"
Giant glossy: "$[AMOUNT]+". Label: "[LOBBY] TOTAL"
Bottom lines: "[FACT 1] | [FACT 2] | [FACT 3]"
Photorealistic editorial sports magazine cover. Barcode. Date stamp.
```

## Collectible Card Format (May 2026 iteration)

After user feedback, evolved from book-cover to **collectible trading card** style:
- **NO borders or book frames** — clean card edges with subtle glow
- **QR code** (bottom right) with "ESCANEAR PARA VER CONEXIONES" — links to full connections website at lobby-tracker URL
- **6+ stats bullet points** — not just 3, include all relevant facts
- **Both ARS and USD** — always convert using historical blue dollar rates (see table below)
- **Footer URL**: website domain
- **Key lesson**: Do NOT over-control the prompt. V6 failed because too many constraints killed GPT Image 2's creative visual metaphors (obelisk, Israeli flag, money stacks, contract papers). The V5 prompt let GPT be creative and it delivered excellence. Only tweak ONE thing at a time (e.g. spacing).

## jq Extraction Trick (faster than Python for large responses)

```bash
# For 2MB+ responses, jq is faster than Python's json module:
jq -r '.choices[0].message.images[0].image_url.url' /tmp/card.json | cut -d, -f2 | base64 -d > /tmp/output.png
```

## Currency Conversion: Argentina Blue Dollar

ALWAYS convert ARS amounts to USD using the historical "dólar blue" rate for the transaction date.

| Year | Blue Dollar Range | Midpoint |
|---|---|---|
| 2021 | $141 - $208 | ~$180 ARS/USD |
| 2022 | $200 - $346 | ~$280 ARS/USD |
| June 2022 | ~$240 | ~$240 ARS/USD |
| 2023 | $346 - $1,025 | ~$600 ARS/USD |

Format: `ARS $2.400.000.000+` / `≈ USD $8.000.000+`
Sources: cotizacion-dolar.com.ar, bloomberglinea.com

## Card Evolution History

This documents the iterative feedback loop — useful for future card generation to avoid repeated mistakes:

1. **V1 (Nano Banana Pro)**: Generic dark infographic, 4-square grid → **REJECTED**. "No se parece en NADA a AIPAC Tracker."
2. **V2 (Nano Banana 2)**: Red card, silhouette, dollar amount → **MISSED (wasn't delivered)**. Too flat, lacked punch.
3. **V3 (GPT Image 2)**: Red card with stats, barcode → **REJECTED**. "Le falta ese punch típico de imagen2."
4. **V4 (GPT Image 2)**: Sports magazine cover, cinematic, silhouette, high angle → **APPROACH CORRECT**. User said "Va queriendo. La posición del personaje y su forma es excelente."
5. **V5 (GPT Image 2)**: Collectible card, no borders, QR, ARS+USD, 6 stats, villain energy, high angle, electric lightning, obelisk + Israeli flag visual metaphors → **FINAL DESIGN — APPROVED**. User said \"Excelente. Me encanta. Podes manejar un poco mejor el posicionamiento de las cosas.\"
6. **V6 (GPT Image 2)**: Attempted to fix text spacing but OVER-CONTROLLED the prompt → **REJECTED**. Lost creative visual elements (obelisk, flag, money). User: \"Donde esta el obelisco la bandera de Israel qué estaba en la otra imagen, el contrato y los dolares, le quedaba muy bien! La cagaste con la última imagen.\"
7. **V7 (GPT Image 2)**: Restored original V5 prompt, only added spacing + \"let the model be creative with visual metaphors\" → **FINAL APPROVED.** User: \"Hermoso. Ya estamos con el diseño. Dejalo fijo así.\"

Key learnings across iterations:
- GPT Image 2 >> Nano Banana for this use case
- Magazine sports cover aesthetic > flat infographic
- HIGH ANGLE villain perspective resonated strongly
- Always include BOTH ARS and USD
- QR code > barcode (functional purpose)
- Collectible trading card > book layout
- 6+ detailed stats > 3 bullet points
- **CRITICAL: Do NOT over-control the prompt.** V6 was worse because too many layout constraints killed GPT's creativity. Let the model add visual metaphors (obelisk, flag, money, papers). Only change ONE thing per iteration.

## Animating Tracker Cards into GIF/MP4

Use this sub-workflow when the user asks to animate an existing political tracker card, make an impact GIF/video for a detail page/social post, or mimic the mood of a reference short without relying on the original video file.

### Preferred input order

1. **Use the approved source image** if present (the exact card/poster the user liked).
2. If the exact image is missing, recover it from likely paths before asking:
   - `~/.hermes/image_cache/`
   - `/tmp/` (`nano_card.png`, `gpt2_*.json`, `tracker_card.png`, etc.)
   - session logs with `session_search` or direct `~/.hermes/sessions/*` search for `MEDIA:`, `data:image`, `gpt2_v`, `Hermoso`, `obelisco`, `bandera`.
3. If still missing, use a project screenshot or current site card as a temporary demo only, and tell the user the exact image will produce a better result.

### When YouTube/Shorts download is blocked

YouTube Shorts often fail from Oracle/datacenter IPs with `Sign in to confirm you’re not a bot`, even with fresh `yt-dlp`. Try the standard fast path first:

```bash
python3 -m venv /tmp/ytdlpvenv
/tmp/ytdlpvenv/bin/pip install -q -U yt-dlp
/tmp/ytdlpvenv/bin/yt-dlp --no-playlist --force-ipv4 \
  --extractor-args 'youtube:player_client=web_creator,ios' \
  -f 'bv*[height<=720]+ba/b[height<=720]/best' \
  -o '/tmp/reference_short.%(ext)s' 'https://youtube.com/shorts/VIDEO_ID'
```

If blocked, do not stall. First use YouTube oEmbed to recover basic metadata/thumbnail/title for style clues without downloading the video:

```bash
curl -sS 'https://www.youtube.com/oembed?url=https://www.youtube.com/shorts/VIDEO_ID&format=json'
```

Then treat the short as a **style reference** and recreate the effect procedurally: jump cuts/glitch slices, red/blue chromatic offsets, sudden zooms, scanlines, flicker, red impact flashes, grain/VHS noise, and short-form pacing. For a CapCut/terror edit, a square or vertical card with punch zooms and 1-frame dark/red flashes can work even without the original video.

### Procedural GIF/MP4 recipe

A reliable no-GPU path:

1. Ensure tools:
   ```bash
   python3 -m venv /tmp/gifvenv
   /tmp/gifvenv/bin/pip install -q pillow numpy imageio
   command -v ffmpeg
   ```
   If the active Hermes Python lacks `pip` or imports still fail, use the system Python path instead:
   ```bash
   sudo apt-get update
   sudo apt-get install -y python3-pil python3-numpy
   /usr/bin/python3 - <<'PY'
   import PIL, numpy
   print('ok')
   PY
   ```
2. Create frames with Pillow/NumPy:
   - vertical `540x960` or `720x1280`
   - darkened/zoomed source card or screenshot background
   - red radial rays behind the politician/card
   - glowing symbolic elements (flag/contract/money) as overlays
   - card/person rising from bottom-center using ease-out cubic motion
   - 1-3 frame glitch cuts with horizontal roll and RGB channel offsets
   - scanlines + vignette for short-video tension
3. Encode both GIF and MP4:
   ```bash
   # GIF via Pillow for portability; keep <= ~8MB when possible
   # MP4 is much smaller and better for web/Telegram
   ffmpeg -y -framerate 15 -i /tmp/frames/frame_%03d.png \
     -vf 'format=yuv420p' -movflags +faststart public/larreta-impact-demo.mp4
   ```
4. Verify a mid-frame with `vision_analyze` before sending.

### OpenRouter video / Veo 3.1 motion-poster workflow

Use this when the user asks to make a higher-impact video from a static tracker card using OpenRouter video models (e.g. `google/veo-3.1`) or wants a YouTube Shorts/Reels-style motion poster.

1. **Survey available video models and pricing before submitting jobs**:
   ```bash
   set -a; . ~/.hermes/.env; set +a
   /usr/bin/python3 - <<'PY'
   import os, requests
   j=requests.get('https://openrouter.ai/api/v1/videos/models',
     headers={'Authorization':'Bearer '+os.environ['OPENROUTER_API_KEY']}, timeout=30).json()
   for m in j['data']:
     if 'veo' in m['id'] or 'google' in m['id']:
       print(m['id'], m.get('supported_resolutions'), m.get('supported_aspect_ratios'),
             m.get('supported_durations'), m.get('pricing_skus'))
   PY
   ```
   As of May 2026, `google/veo-3.1` supports `/api/v1/videos` with `aspect_ratio`, `duration`, `resolution`, `generate_audio`, `frame_images`, and polling via `polling_url`. `google/veo-3.1-fast` and `google/veo-3.1-lite` are cheaper iteration options.

2. **For image-to-video attempts**, publish the source card under `public/` first so OpenRouter can fetch it:
   ```bash
   cp ~/.hermes/image_cache/<approved-card>.jpg public/media/source-card.jpg
   vercel --prod --yes
   ```

3. **Submit the job and poll**:
   ```python
   import os, json, requests, pathlib, time
   prompt = pathlib.Path('assets/video-ref/veo_prompt.txt').read_text()
   payload = {
     'model': 'google/veo-3.1',
     'prompt': prompt,
     'aspect_ratio': '9:16',
     'duration': 8,
     'resolution': '720p',
     'generate_audio': False,
     'frame_images': [{
       'type': 'image_url',
       'frame_type': 'first_frame',
       'image_url': {'url': 'https://<site>/media/source-card.jpg'}
     }]
   }
   r = requests.post('https://openrouter.ai/api/v1/videos',
     headers={'Authorization':'Bearer '+os.environ['OPENROUTER_API_KEY'], 'Content-Type':'application/json'},
     json=payload, timeout=60)
   r.raise_for_status()
   polling_url = r.json()['polling_url']
   # GET polling_url with the same Authorization header until status is completed/failed.
   # Download returned content URLs WITH Authorization header; unsigned_urls may still require auth.
   ```

4. **If Veo/Vertex filters image-to-video with real politicians or sensitive poster text**, do not burn repeated full-price retries. Use a two-layer approach:
   - Generate a neutral 9:16 red/black investigative **motion background** with no real names, no readable political text, no real people, no claims.
   - Composite the approved card/poster locally on top with Pillow/ffmpeg, preserving the exact source image and adding zoom pulses, shake, scanlines, RGB split, glitch bars, and subtitles.
   - This keeps the factual poster unchanged while using Veo only for cinematic motion texture.

   Safe background prompt pattern:
   ```text
   Create an 8-second vertical 9:16 motion-poster video for a dark investigative documentary teaser. Red-and-black editorial thriller, polished YouTube Shorts/CapCut-style glitch edit. A stylized graphic poster fills the frame: a stern adult male figure in a dark suit is centered in shadow, surrounded by abstract documents, money-like paper shapes, a city monument silhouette, and a dark flag-like graphic background. Bold white headline blocks are abstract poster typography. Do not render readable real names, numbers, logos, political claims, country names, or QR codes. Slow cinematic push-in, three hard zoom-punch beats, red lightning flicker, parallax, VHS grain, scanlines, chromatic aberration, horizontal glitch bars, micro camera shake, red flash frames, final one-second hold for loop. No gore, no weapons, no physical harm, no real people, no readable political text.
   ```

5. **Composite locally**:
   - Decode Veo MP4 frames with `ffmpeg -i veo-bg.mp4 /tmp/bg/frame_%04d.png`.
   - Place the approved poster/card centered over the background; for vertical videos, keep the card around `690x690` on a `720x1280` canvas.
   - Use slow push-in plus beat pulses around `1.5s`, `4.0s`, `6.2s`.
   - Add subtitle/CTA only if desired; avoid adding any new factual claims.
   - Export MP4 for web and a smaller GIF for previews.

6. **Verify**:
   - Create a contact sheet from 3-4 frames and run `vision_analyze` for cropping/readability.
   - `ffprobe` the MP4 and `curl` deployed asset URLs.

### OpenRouter/content-policy fallback

Image generation/editing/video prompts using real politicians + ominous language + national/religious symbols may return `PROHIBITED_CONTENT`, Vertex usage-guideline errors, or “completed with no output (content may have been filtered)”. If that happens:

- Do **not** keep retrying the same prompt.
- For static image generation/editing: use the already-approved/static card as the source and animate locally.
- For Veo/video: generate a neutral motion background with no real names/claims/readable political text, then composite the approved card locally.
- Keep the visual editorial, not defamatory: labels should reflect the project’s documented tracker framing, while evidence claims remain on the site/DB.

### Integration note

For a Next.js project, save assets under `public/` so they can be referenced as `/larreta-impact-demo.gif` or `/larreta-impact-demo.mp4`. Prefer MP4 in the page for size/performance, with GIF for chat previews.

## Pitfalls

- **GPT Image 2 timeout**: use `--max-time 300` minimum; the model renders slowly (sometimes 60-120s)
- **Base64 decoding**: output is `data:image/png;base64,...` — split on comma, decode part [1]
- **Large responses**: A 2.3MB response JSON takes ~10s to base64 decode — use heredoc Python, not one-liner
- **Nano Banana timeout**: even slower than GPT Image 2; reduce prompt complexity
- **Text hallucination**: ALWAYS verify generated text with vision_analyze before sending to user
- **OpenRouter routing**: GPT Image 2 requires OpenAI API key configured in OpenRouter; Nano Banana works with Google AI keys
- **Empty curl responses**: If curl times out, check file size (0 bytes = curl failed, retry)
- **Exact approved image missing**: search caches/session logs first; if unavailable, create a demo from a site screenshot but clearly ask for the exact image for final quality.
- **GIF size**: vertical GIFs get large quickly; also export MP4 because it is usually 10-50x smaller.
- **Hermes venv may not have pip/Pillow**: if `python3 -m pip` says `No module named pip` or Pillow imports fail, install `python3-pil python3-numpy` with apt and run generation scripts with `/usr/bin/python3`.
- **Font path drift**: `DejaVuSansCondensed-Bold.ttf` may not exist; search `/usr/share/fonts/**/*.ttf` and fall back to `/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf`.
- **Short download blocked**: use oEmbed metadata for title/thumbnail/context, then recreate the style locally rather than waiting on yt-dlp/CDP.

The user has provided the following instruction alongside the skill invocation: [IMPORTANT: You are running as a scheduled cron job. DELIVERY: Your final response will be automatically delivered to the user — do NOT use send_message or try to deliver the output yourself. Just produce your report/output as your final response and the system handles the rest. SILENT: If there is genuinely nothing new to report, respond with exactly "[SILENT]" (nothing else) to suppress delivery. Never combine [SILENT] with content — either report your findings normally, or say [SILENT] and nothing more.]

Contexto: Chicho pidió continuar el proyecto Lobby Tracker Argentina cuando se resetee el límite. Proyecto en /home/ubuntu/lobbytracker, live en https://lobbytracker.vercel.app. Supabase project ref xvrlnhwbvyyydnnzctbk. Usar credenciales del entorno: SUPABASE_ACCESS_TOKEN, VERCEL_TOKEN, OPENROUTER_API_KEY si está disponible. Responder en español directo, sin filler.

Nota operativa: el cron weekly permanente `f5f4a92124c2` fue pausado para que no se duplique/solape con este run pesado. Al terminar correctamente este trabajo, reanudarlo con cronjob action='resume', job_id='f5f4a92124c2'.

Tareas en orden:

1) Reintentar el video de Larreta con Gemini/Veo via OpenRouter, buscando mejor efecto y especialmente audio. Usar google/veo-3.1 o variante disponible si conviene. Optimizar prompt para obtener un efecto más impactante que el composite actual, idealmente con audio cinematográfico/suspenso si el modelo lo permite. Si la imagen-to-video con el afiche real es filtrada, probar al menos 3 alternativas autónomas: prompt más neutral, generar motion layer con audio y compositar, usar Veo Fast/Lite o parámetros distintos. Guardar artefactos en /home/ubuntu/lobbytracker/public/media/ y actualizar la página si el resultado mejora el actual. Verificar build/deploy.

2) Agregar 5 políticos más al tracker. Desplegar subagentes en paralelo, uno por político, para encontrar conexiones/rastros públicos de lobby israelí o vínculos institucionales relevantes: contratos, viajes, nombramientos, eventos con DAIA/AMIA/embajada/CCAI, seguridad/defensa, procurement, causas judiciales, financiamiento electoral cuando esté documentado. Reglas: NO inventar datos. Toda conexión debe tener fuente pública, link, fecha, excerpt, tipo de conexión, grupo/actor relacionado y montos si existen. Priorizar fuentes primarias (Boletín Oficial, BAC/Compr.ar, Comprar, sitios oficiales, justicia) y periodismo creíble como apoyo. Insertar en Supabase vía Management API con evidence rows obligatorias y dates casteadas como ::date. Actualizar totals por político. Mantener RLS, región, colores, card design y status system sin tocar.

3) Deployar con: cd /home/ubuntu/lobbytracker && vercel --prod --yes. Verificar live 200, REST de Supabase, y que cada nuevo connection tenga evidence(source_url, source_name, excerpt). Reanudar el weekly cron `f5f4a92124c2`. Entregar reporte corto: políticos agregados, conexiones insertadas, fuentes usadas, pendientes/manual review, URLs finales.

## Response

## Lobby Tracker Argentina — run pesado completado

- Live site: **200 OK**
- Deploy prod: **OK**
- Alias final: https://lobbytracker.vercel.app
- Weekly cron reanudado: `f5f4a92124c2`
- Supabase REST: **OK**
- Nuevos políticos agregados: **5**
- Nuevas conexiones insertadas: **15**
- Evidence rows nuevas: **15/15 OK** con `source_url`, `source_name`, `excerpt`
- Manual review: **0 inserciones dudosas**; lo no suficientemente primario quedó fuera.

## Video Larreta / Veo 3.1

Se reintentó con OpenRouter/Veo:

1. **Imagen real → video con audio** usando poster de Larreta: falló por filtro de contenido / “completed with no output”.
2. **Motion layer neutral con audio, Veo 3.1 Fast**: completó.
3. **Motion layer neutral con audio, Veo 3.1 Lite**: completó.
4. **Motion layer sin audio para fallback**: completó.

Resultado elegido: **Veo 3.1 Fast neutral + composite local del afiche real + audio cinematográfico**.

Archivos deployados:

- MP4 con audio: https://lobbytracker.vercel.app/media/larreta-veo31-final-audio.mp4
- GIF preview: https://lobbytracker.vercel.app/media/larreta-veo31-final-audio.gif
- Alternativas guardadas:
  - `/media/larreta-veo31-attempt2_neutral_audio.mp4`
  - `/media/larreta-veo31-attempt3_lite_audio.mp4`
  - `/media/larreta-veo31-attempt4_noaudio_bg.mp4`

Página actualizada para usar el nuevo MP4 con **controls** para reproducir audio.

## Políticos agregados

### Javier Milei

Conexiones insertadas:

- `2024-02-07` — viaje oficial / reunión con Netanyahu — Gobierno del Estado de Israel  
  Fuente: https://www.argentina.gob.ar/noticias/el-presidente-milei-se-reunio-con-el-primer-ministro-de-israel-benjamin-netanyahu

- `2024-07-17` — evento institucional antiterrorismo con CJL / AMIA / DAIA  
  Fuente: https://www.casarosada.gob.ar/informacion/discursos/50580-palabras-del-presidente-javier-milei-en-la-conferencia-internacional-sobre-seguridad-y-antiterrorismo

- `2024-12-02` — cooperación defensa / seguridad Argentina-Israel  
  Fuente: https://www.argentina.gob.ar/noticias/argentina-e-israel-fortalecen-alianza-estrategica-en-materia-de-defensa

### Patricia Bullrich

Conexiones insertadas:

- `2016-01-22` — reunión diplomática con Embajada de Israel  
  Fuente: https://www.argentina.gob.ar/noticias/gjunto-la-embajadora-de-israel

- `2016-11-14` — viaje oficial a Israel / visita a SIBAT  
  Fuente: https://argentina.gob.ar/noticias/gla-ministra-bullrich-comenz%C3%B3-su-visita-israel

- `2017-01-02` — contrato / compra a Israel por **USD 84.000.000**  
  Fuente: https://www.lanacion.com.ar/politica/el-gobierno-le-compro-a-israel-cuatro-lanchas-y-sistemas-para-el-control-de-fronteras-por-us-84-millones-nid1972296/

Total actualizado Bullrich: **USD 84.000.000**

### Jorge Macri

Conexiones insertadas:

- `2023-09-20` — encuentro electoral organizado por AMIA  
  Fuente: https://www.amia.org.ar/2023/09/20/amia-invita-al-ciclo-de-encuentros-con-candidatos-a-jefe-de-gobierno/

- `2024-11-21` — Encuentro Empresarial Argentina-Israel / CCAI / Embajada  
  Fuente: https://www.argentina.gob.ar/noticias/la-uif-estuvo-presente-en-el-encuentro-empresarial-argentina-israel-2024

- `2025-01-22` — reunión institucional con DAIA  
  Fuente: https://daia.org.ar/2025/01/22/reunion-con-el-jefe-de-gobierno-porteno/

### Waldo Wolff

Conexiones insertadas:

- `2015-05-01` — cargo institucional / vicepresidente DAIA  
  Fuente: https://prod.eldestapeweb.com/nota/desde-la-daia-dicen-que-la-relacion-con-el-gobierno-esta-muy-sensible--2015-5-1-9-33-0

- `2016-11-17` — misión seguridad/defensa en Israel / SIBAT  
  Fuente: http://www.infobae.com/politica/2016/11/17/patricia-bullrich-visito-puntos-de-control-fronterizos-del-ejercito-de-israel/

- `2024-11-22` — Encuentro Empresarial Argentina-Israel / CCAI  
  Fuente: https://ccai.org.ar/encuentro-empresarial-argentina-israel-2024/

### Gerardo Werthein

Conexiones insertadas:

- `2024-11-22` — Encuentro Empresarial Argentina-Israel / CCAI  
  Fuente: https://ccai.org.ar/encuentro-empresarial-argentina-israel-2024/

- `2024-12-05` — acto DAIA / apoyo público a Israel  
  Fuente: https://agenciaajn.com/noticia/la-daia-renueva-su-consejo-directivo-con-un-fuerte-mensaje-de-solidaridad-hacia-israel-253516

- `2025-02-02` — viaje oficial a Israel / reunión con Gideon Sa’ar  
  Fuente: https://www.cancilleria.gob.ar/es/actualidad/noticias/visita-israel-el-canciller-werthein-se-reunio-con-su-par-israeli-y-mantuvo-un

## Verificación

- Build local: **OK**
- Vercel prod deploy: **OK**
- Live home: **200**
- Nuevo MP4: **200**, `video/mp4`, con audio AAC
- Nuevo GIF: **200**, `image/gif`
- Supabase politicians: **6 total**
- Nuevas conexiones verificadas: **15**
- Nuevas conexiones sin evidence: **0**

Nota: siguen existiendo **7 conexiones viejas de Larreta sin evidence rows** heredadas del seed anterior. No las toqué en este run porque la tarea era agregar nuevos políticos/conexiones con evidencia obligatoria; las nuevas quedaron completas.
