captchaforge 0.2.36

[DO NOT USE — UNDER ACTIVE DEVELOPMENT, NOT PRODUCTION-READY] Captcha solver scaffolding for chromiumoxide-driven browsers. The architecture is in place (vendor solvers, retry-loop iframe walking, VLM provider abstraction, real-WAF bench harness) but the live-vendor success rate is still 0% — Cloudflare Turnstile / hCaptcha / reCAPTCHA detect us at a TLS / CDP fingerprint layer that no flag-based stealth has cleared. Watch the repo; do not depend on this for any real workload.
Documentation
# Contributing to captchaforge

## Getting Started

```bash
git clone https://github.com/santhsecurity/captchaforge
cd captchaforge
cargo test --workspace
```

## Development Workflow

1. **Fork & branch**: `git checkout -b feature/my-feature`
2. **Write tests first**: Add property tests for new invariants, integration tests for browser behavior
3. **Implement**: Follow existing code style, keep functions under 50 lines where possible
4. **Run quality gates**:
   ```bash
   cargo fmt
   cargo clippy --workspace -- -D warnings
   cargo test --workspace
   cargo test --test integration -- --ignored --test-threads=1
   ```
5. **Update docs**: If you change public API, update `ARCHITECTURE.md` and rustdoc
6. **PR**: Fill out the PR template, reference any issues

## Code Review Checklist

- [ ] Tests added for new behavior
- [ ] Property tests added for invariants
- [ ] No `unsafe` code (forbidden by lint)
- [ ] No `unwrap()` or `expect()` in production paths without justification
- [ ] `cargo clippy -- -D warnings` passes
- [ ] `cargo fmt` passes
- [ ] Documentation updated
- [ ] CHANGELOG.md updated

## Test Tiers

| Tier | Location | Speed | Browser |
|------|----------|-------|---------|
| Unit | Inline in `src/` | <1s | No |
| Property | `tests/property_*.rs` | <10s | No |
| Snapshot | `tests/snapshot_*.rs` | <5s | No |
| Chaos | `tests/chaos_resilience.rs` | <5s | No |
| Integration | `tests/integration.rs` | <2min | Yes |
| Bench | `bench/src/suites/` | <20min | Yes |

## Adding a New Solver

1. Implement `CaptchaSolver` trait
2. Add builder methods for configuration
3. Add unit tests in `src/solver.rs` or `tests/property_solver.rs`
4. Add integration test in `tests/integration.rs`
5. Register in `CaptchaSolverChain::default_chain()` if generally useful
6. Update `ARCHITECTURE.md`

## Adding a New Provider Rule (TOML)

Most new vendors do **not** need any Rust code — they're added as a
TOML entry in `rules/community.toml`. The schema:

```toml
[[provider]]
name           = "vendor-slug"     # lowercase + underscores; no spaces
priority       = 50                # lower runs first; built-ins reserve 5..100
solver_names   = ["BehavioralCaptchaSolver", "VlmCaptchaSolver"]   # optional

[provider.triggers]
selectors            = ["[data-vendor-x]"]            # any selector matching = fire
window_globals       = ["VendorSDK", "_vendor_x"]     # typeof !== undefined = fire
script_src_contains  = ["vendor-cdn.example.com"]     # substring match in <script src>
title_contains       = ["checking your browser"]      # case-insensitive title substring
cookie_names         = ["__vendor_jwt"]               # presence-only (no value match)
```

Rule of thumb: at least two of the five trigger types should match for
a real-vendor entry, so a single false-positive selector doesn't fire
the wrong solver chain. **Detection is OR across triggers** — adding
more triggers expands what you catch; adding fewer makes detection more
specific. Run `cargo test -p captchaforge --lib detect::rules` after
editing to make sure your TOML parses.

## Adding a New Stealth Profile

`StealthProfile` is `#[non_exhaustive]` — adding a variant is a SemVer
*minor*, removing one is *major*. To add `MyBrowser`:

1. Add the variant to `enum StealthProfile` in `src/stealth_profiles.rs`.
2. Add a matching arm in `profile_to_overrides()` returning a fully-
   populated `ProfileOverrides`. Pin a coherent (UA, platform, brands,
   GPU, screen, languages) tuple — mismatches between fields are *more*
   suspicious than vanilla headless.
3. Update the test loops in the same file (`every_chromium_profile_has_brands`,
   `safari_and_firefox_have_no_brands`, `ua_matches_platform`,
   `languages_default_to_english`) to cover the new variant.
4. Add a CLI mapping in `examples/solve_url_simple.rs::profile_from_name`.

## Adding a New SDK Helper

The convenience layer lives in `src/sdk.rs`. Helpers there must:

- Take `&chromiumoxide::Page` (never own the browser).
- Return `anyhow::Result<T>` for any IO-backed work.
- Be **best-effort** — never panic, log on failure with `tracing::debug!`,
  and return a clean failure outcome that callers can ignore.
- Be re-exported from `lib.rs` AND added to `prelude.rs` if they're
  load-bearing for typical usage.

## Release Process

1. Update `CHANGELOG.md`
2. Bump version in `Cargo.toml`
3. Run full test suite
4. `cargo publish`
5. Tag release on GitHub