# 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
| 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