captchaforge 0.2.39

Captcha detection and solving for Firefox and BiDi-driven browsers. Detection, vendor solver scaffolding, trusted cross-origin click delivery into nested OOPIFs, and stealth personas are implemented and tested; broad live-vendor solve rates are not yet benchmarked.
Documentation
# VLM Training Runbook

The captchaforge VLM solver currently relies on whichever vision
model the operator runs in Ollama. We want to ship a bundled
captchaforge-vlm model that out-performs generic models on the
specific tasks captchaforge dispatches (image-grid selection,
slider gap detection, rotated text, color match).

## Pipeline

```
       1. capture                2. label                  3. train                4. distill              5. promote
TrainingCorpus  →  VlmDataset (sha-content-id)  →  LoRA Qwen2-VL-7B  →  7B → 2B  →  Ollama tag
   (live solves)    auto_label.py teacher              train_lora.py        distill.py    promote_to_ollama.sh
```

Each stage already has a script in `training/scripts/`. Today none
of them have been run end-to-end, the pipeline plumbing is
complete; the training data + GPU time + model upload are external
to this session.

## Stage 1: Capture

The bench's `TrainingCorpus` opt-in already captures failed solves
into `<corpus-root>/<vendor>/*.jsonl`. Operators running
captchaforge in production with `with_training_corpus(...)` are
already accumulating data.

Bootstrap: run the bench suite against the public test sitekeys
with `--with-network --output corpus-seed`. Each solver failure
emits a sample.

## Stage 2: Label

```bash
python3 training/scripts/auto_label.py \
    --corpus /path/to/corpus \
    --teacher gpt-4v|claude-3-opus|qwen-vl-72b \
    --out training/labeled.jsonl
```

The teacher model labels each captured image with the correct
answer. We use a much larger model than the student we're training.

## Stage 3: Train (LoRA on Qwen2-VL-7B)

```bash
docker build -t captchaforge-training -f training/Dockerfile .
docker run --gpus all -v $(pwd)/training:/work captchaforge-training \
    python /work/scripts/train_lora.py \
        --base Qwen/Qwen2-VL-7B-Instruct \
        --data /work/labeled.jsonl \
        --out /work/checkpoints/captchaforge-vlm-7b
```

Compute: one A100 80GB. ~6-12 hours for ~10k labeled samples.

## Stage 4: Distill (7B → 2B)

Smaller model runs comfortably in 8GB VRAM consumer GPUs, keeps
captchaforge usable for the long tail of operators.

```bash
docker run --gpus all -v $(pwd)/training:/work captchaforge-training \
    python /work/scripts/distill.py \
        --teacher /work/checkpoints/captchaforge-vlm-7b \
        --student Qwen/Qwen2-VL-2B-Instruct \
        --data /work/labeled.jsonl \
        --out /work/checkpoints/captchaforge-vlm-2b
```

## Stage 5: Promote to Ollama

```bash
bash training/scripts/promote_to_ollama.sh \
    training/checkpoints/captchaforge-vlm-2b \
    captchaforge/captchaforge-vlm:2b
```

Publishes to the captchaforge Ollama namespace. Operators then run:

```bash
ollama pull captchaforge/captchaforge-vlm:2b
captchaforge setup --auto  # picks up the new local model
```

## What's blocking GAP-6

This is the only task where I genuinely can't make progress from
this session, it needs:
- A GPU box (no GPU available in the CI containers; A100 / 4090
  for real LoRA).
- A teacher-model API key with budget for ~50k label requests
  (GPT-4V or Claude).
- Ollama publishing credentials.

The pipeline scripts are in place + verified by `cargo test
--test captchaforge_training_pipeline_exists` (TODO: add this
test).