JSON-Rohbericht maschinenlesbar
{
"data": {
"repo": {
"topics": [],
"is_fork": false,
"size_kb": 2945,
"has_wiki": false,
"homepage": null,
"languages": {
"CSS": 23694,
"HTML": 87597,
"Python": 2167872,
"JavaScript": 100172
},
"pushed_at": "2026-07-29T22:45:14Z",
"created_at": "2026-02-21T23:24:06Z",
"owner_type": "User",
"updated_at": "2026-07-29T22:45:12Z",
"description": "Anti-detection HTTP client for Python that handles TLS fingerprinting, WAF challenge solving, and cookie management.",
"is_archived": false,
"is_disabled": false,
"license_spdx": "Apache-2.0",
"default_branch": "main",
"license_spdx_raw": "Apache-2.0",
"primary_language": "Python",
"significant_languages": [
"Python"
]
},
"owner": {
"blog": null,
"name": "Avery L.",
"type": "User",
"login": "Averyy",
"company": null,
"location": "Canada",
"followers": 9,
"avatar_url": "https://avatars.githubusercontent.com/u/3880328?v=4",
"created_at": "2013-03-16T02:50:43Z",
"is_verified": null,
"public_repos": 13,
"account_age_days": 4883
},
"license": {
"state": "standard",
"spdx_id": "Apache-2.0",
"raw_spdx": "Apache-2.0",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [
{
"tag": "v0.4.3",
"kind": "patch",
"published_at": "2026-07-29T22:45:02Z"
},
{
"tag": "v0.4.2",
"kind": "patch",
"published_at": "2026-07-29T14:39:49Z"
},
{
"tag": "v0.4.1",
"kind": "patch",
"published_at": "2026-07-28T16:20:24Z"
},
{
"tag": "v0.4.0",
"kind": "minor",
"published_at": "2026-07-27T19:26:01Z"
},
{
"tag": "v0.3.4",
"kind": "patch",
"published_at": "2026-07-26T15:48:52Z"
},
{
"tag": "v0.3.3",
"kind": "patch",
"published_at": "2026-07-18T23:19:18Z"
},
{
"tag": "v0.3.2",
"kind": "patch",
"published_at": "2026-07-18T14:06:42Z"
},
{
"tag": "v0.3.1",
"kind": "patch",
"published_at": "2026-07-17T18:01:24Z"
},
{
"tag": "v0.3.0",
"kind": "minor",
"published_at": "2026-07-03T14:43:36Z"
},
{
"tag": "v0.2.4",
"kind": "patch",
"published_at": "2026-06-07T19:59:18Z"
},
{
"tag": "v0.2.3",
"kind": "patch",
"published_at": "2026-06-07T15:01:11Z"
},
{
"tag": "v0.2.2",
"kind": "patch",
"published_at": "2026-06-06T20:50:18Z"
},
{
"tag": "v0.2.1",
"kind": "patch",
"published_at": "2026-05-11T14:20:03Z"
},
{
"tag": "v0.2.0",
"kind": "minor",
"published_at": "2026-04-05T15:43:41Z"
},
{
"tag": "v0.1.9",
"kind": "patch",
"published_at": "2026-03-06T17:30:48Z"
},
{
"tag": "v0.1.8",
"kind": "patch",
"published_at": "2026-03-05T21:26:41Z"
},
{
"tag": "v0.1.7",
"kind": "patch",
"published_at": "2026-03-02T20:31:57Z"
},
{
"tag": "v0.1.6",
"kind": "patch",
"published_at": "2026-03-02T15:54:34Z"
},
{
"tag": "v0.1.5",
"kind": "patch",
"published_at": "2026-02-27T18:14:27Z"
},
{
"tag": "v0.1.4",
"kind": "patch",
"published_at": "2026-02-26T03:16:39Z"
},
{
"tag": "v0.1.3",
"kind": "patch",
"published_at": "2026-02-25T14:33:24Z"
},
{
"tag": "v0.1.2",
"kind": "patch",
"published_at": "2026-02-24T20:18:51Z"
},
{
"tag": "v0.1.1",
"kind": "patch",
"published_at": "2026-02-24T17:53:52Z"
},
{
"tag": "v0.1.0",
"kind": "minor",
"published_at": "2026-02-23T23:30:40Z"
}
],
"recent_commits": [
{
"oid": "b673126e7b5ff33c7e6fb76bbc993610750b92d0",
"body": "Validate target DOM and distinguish browser passthrough from transport clearance.\n\nCorrect iframe geometry, render classification, and bounded solver cleanup. Add regression coverage and update the solver documentation.",
"is_bot": false,
"headline": "Fix Alibaba TMD browser solving",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-07-29T22:45:02Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c9c70775b807498286f342b435e95cb8cd293184",
"body": "Fixed and released in v0.4.2. The findings it carried are preserved:\nairmatrix.ca is recorded in docs/site-list.md as the live regression\ntarget for cloudflare_block, and the block page itself is checked in at\ntests/fixtures/cloudflare_waf_block_1020.html.",
"is_bot": false,
"headline": "Remove the resolved Cloudflare WAF block TODO",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-07-29T14:55:53Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "219e410d586750dcaa74a8d2c692792180c3f72f",
"body": "Three fixes from a crawler bug report against 0.4.1.\n\nsession.render(url) loads a page in the browser solver, waits for\nclient-side rendering to settle, and returns the finished document as a\nWaferResponse. Some pages ship a shell and write their content with\nJavaScript, so no fingerprint recovers m\n[…]\nd by the resolver, not\nunreachable, but the transport can only report a refused connection to\n[::]:443, which reads like a dead site. Resolved on the failure path\nonly, so the happy path pays nothing.",
"is_bot": false,
"headline": "Add browser-rendered fetch, terminal WAF blocks, DNS sinkhole diagnosis",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-07-29T14:39:49Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "305ee080f0fe4a1894d42509dd68e64817bf6dff",
"body": "- add fixed-origin Reddit browser cookie recovery for sync and async sessions\n- return validated Cloudflare browser responses without pinning or rebuilding\n- expand regression coverage and update consumer and live-site documentation",
"is_bot": false,
"headline": "Fix Reddit recovery and Cloudflare passthrough",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-07-28T16:20:24Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7e255d276566985a48b96214aad0ddd7c509301e",
"body": "Spot-checking the other solvers headless after the init-script fallback\nlanded: Cloudflare (200, 11.8s), Kasada (200/687KB, 12.7s) and Alibaba Baxia\n(18/18) all pass, DataDome does not -- ChallengeDetected, with\n_verify_headless_patches reporting outerWidth=1440 innerWidth=1440\ncolorDepth=24.\n\nThat \n[…]\nonditional, with the wellfound row\ncarrying the same caveat.\n\nHeaded was re-verified after the shared-path change and is unaffected:\nCloudflare 12.8s, DataDome 6.0s, Kasada 7.5s, Akamai 9.2s, all 200.",
"is_bot": false,
"headline": "docs: record that headless is fixed for some WAFs, not DataDome",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-07-27T19:26:01Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "69e6970eece12d5e20635289cb606d71448ac96e",
"body": "…ation\n\nTesting drag replay headless showed the slider solving and earning no\ntarget-scoped x5sec three rounds running, ending in ChallengeDetected, where\nthe same burst headed returned real results.\n\nThe drag code was not at fault. Under Patchright with Chrome 150 on macOS,\nPage.addScriptToEvaluate\n[…]\nuture regression is loud instead of silent. The residual\nlimitation is documented: this lands just after document-start, so a WAF that\nfingerprints at document-start could still read pre-patch values.",
"is_bot": false,
"headline": "fix: make headless viable by re-applying fingerprint scripts on navig…",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-07-27T18:53:16Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "26164f1c952b2929239b42b304c1bda55fa17c85",
"body": "An API-vs-docs audit in both directions found two public session methods\nabsent from llms.txt. Both exist on SyncSession and AsyncSession, both need a\nbrowser_solver=, and both return bool meaning \"browser state was earned and\nimported\" -- not that the caller's application request succeeded, which i\n[…]\ne audit now reports clean in all four directions: no exported name or\npublic session method is undocumented, and no wafer.X or session.X symbol\ncited in llms.txt or README is missing from the package.",
"is_bot": false,
"headline": "docs: document browser_prime, browser_solve_challenge, and __version__",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-07-27T17:08:03Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "5b3442649bdc2941178f4c3fd1b494b42a58d081",
"body": "…lback\n\nFollow-up to the feature commit: four consumer-visible behaviours were\nchanged or added without matching docs.\n\n- get_cookie(): the RFC 6265 rewrite changed what it returns. llms.txt and\n README still described \"exact-host first, then parent-domain\", which no\n longer holds -- a host-only c\n[…]\nn-coordinate probe authorizes a toString-visible\n override, so an inconclusive result must leave it off rather than abort.\n Documents the real headless Chrome 150 geometry that made it inconclusive.",
"is_bot": false,
"headline": "docs: document cookie scoping, reCAPTCHA gating, and the screenxy fal…",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-07-27T17:04:20Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3d5059104d3d478af73fa84d5367195c2319345a",
"body": "Bundles six work streams that had accumulated uncommitted, plus fixes for\ndefects found reviewing and live-testing them.\n\nNew:\n- Profile.IOS_SAFARI: wire-verified iPhone Safari 26.5.2 TLS/H2/header\n identity. JA3, JA4_b and JA4_c are recomputed from the module's own\n constants in tests, which pins\n[…]\ng, Reddit bootstrap, Imperva, and AsyncSession\nincluding 4 concurrent coroutines. AWS WAF, F5 Shape and PX never\nchallenged, so their solvers are unexercised; DataDome is blocked by an\nIP/device flag.",
"is_bot": false,
"headline": "feat: iOS Safari profile, Chrome 150 identity pinning, solver hardening",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-07-27T16:48:06Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ade90aea8653e55c4a49b73b4c9c986a9c77fbe7",
"body": null,
"is_bot": false,
"headline": "docs: record v0.3.4 release",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-07-26T15:51:29Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "14959e81e5f0a74ad294221b8d1692bbf0b572ca",
"body": "- validate and persist anonymous verification in sync and async sessions\n- cover concurrency, deadlines, response caps, and explicit Old Reddit behavior\n- fix encoded GET-form submissions for the Amazon inline solver",
"is_bot": false,
"headline": "fix: move Reddit bootstrap to New Reddit",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-07-26T15:48:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1d27b660b107a81e2edefc82e39fe53cf8905f48",
"body": "- detect Reddit cold-session block pages and warm cookies via old Reddit\n- persist both cookie response legs and cover sync, async, and cache behavior",
"is_bot": false,
"headline": "fix: bootstrap Reddit JSON sessions",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-07-18T23:19:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "587ef0a0003b587254a16ece7f3b5d1d2e50d261",
"body": "Patchright's Chromium (Chrome 150) is newer than wreq's newest Emulation\n(Chrome 149), so the post-solve pin block silently no-opped:\nemulation_for_version(150) returned None. WAF clearance cookies\n(cf_clearance, DataDome) bind to the solving browser's UA + client hints,\nso the Chrome149 replay was \n[…]\ninned wreq/native path. A\nWARNING now fires when the browser outruns wreq's newest profile (was silent).\n\nWire-verified on miata.net (Cloudflare): 200, clearance persists across\nrequests, 0 rotations.",
"is_bot": false,
"headline": "fix: align replay identity to solving browser after browser solve",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-07-18T14:06:42Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "41a44d96a74ea43cb946cb87c4aba1b54a4ed150",
"body": "Add a resolve= session param (dict[str, list[str]]) so callers can hand wafer a pre-validated host->IP map. The socket connects to those IPs while TLS SNI and cert validation still key on the hostname, closing the TOCTOU DNS-rebinding window. Honored on both the wreq path (DnsOptions) and the native\n[…]\n and add real build numbers for Chrome148/149 and Edge148. Wire-verified Chrome149 sec-ch-ua, Safari H2, Dart HTTP/1.1, and tls_verify; full suite (1122 passed) plus a live regression smoke test pass.",
"is_bot": false,
"headline": "feat: SSRF-safe resolve= DNS pinning; bump wreq to 0.12.1 (Chrome149)",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-07-17T18:01:24Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "337ef97b8244c5eb2213d54f8b858e8e468f6a45",
"body": "- bulk()/max_rotations=0 now returns a persistent empty-200 response\n instead of raising EmptyResponse (matches the 429/challenge gates and\n the documented .bulk() contract)\n- Opera Mini honors the declared charset and returns body bytes exactly:\n legacy-charset pages (windows-1251 etc.) decode c\n[…]\nllms.txt sync: 17 WAF types, DART profile, attempt_timeout and\n max_response_size per-request kwargs, honest DataDome solver caps,\n resp.history typing, broadened timeout guarantee to all transports",
"is_bot": false,
"headline": "fix: pre-release review fixes for v0.3.0",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-07-03T14:43:36Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "387f9cbc87487b1ae6a99d37953510e91e078b7f",
"body": "The timeout= contract now explicitly covers backoff, rate-limit, and 429\nRetry-After waits (not just retries/rotations/solves) in llms.txt, the\nconstructor comments, Mistake #17, and the README rate-limit section -\nmatching the deadline-clamping fixes. A hostile Retry-After can't hold a\ncall past its deadline.",
"is_bot": false,
"headline": "docs: note total timeout also bounds rate-limit and Retry-After waits",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-15T12:21:06Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0af513b2d79124e00a4f1ecded49e26b59f39f4d",
"body": "A wreq-layer timeout is now always bounded by the total timeout= budget and\nsurfaced as WaferTimeout (never ConnectionFailed). Make that explicit in the\nllms.txt raise/return lists and the README exhaustion table, distinguishing a\ngenuine connection error (refused/reset/TLS) from a hang.",
"is_bot": false,
"headline": "docs: document WaferTimeout on server hang past total timeout",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-14T14:09:05Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "bf230975a793106f4ec583105902dbe814bf31e2",
"body": "A code review of 5ea9141 (timeout= as a total budget) surfaced a cluster of\ndeadline-bypass bugs that the always-set deadline made reachable. Fixes:\n\n- Exception classification: every attempt now carries a timeout kwarg (the\n remaining-budget clamp, even with no attempt_timeout), so any wreq\n Time\n[…]\nss-\nretries (real sleeps consume the budget; the shared-time.sleep-patch trap is\navoided). 1075 pass, ruff clean. sync/async kept mirrored; re-reviewed by\ncorrectness, security, and regression agents.",
"is_bot": false,
"headline": "fix: close deadline-bypass holes exposed by the total-budget timeout",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-14T14:08:05Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "5ea9141314ec2138e6053ed005f8f5aa4fe92d3b",
"body": "Previously a per-request timeout= was the total call deadline, but a\nsession-level timeout= was only the per-attempt default (the wreq client\ntimeout) and did NOT cap total time across retries/rotations - so\nSyncSession(timeout=30) could run several times over. Now timeout= is the\nTOTAL budget for t\n[…]\nevel timeout= now caps total time. A\nmulti-retry or browser-solve flow that relied on the old per-attempt semantics\nshould raise its timeout= and/or set attempt_timeout=.\n\n1071 tests pass, ruff clean.",
"is_bot": false,
"headline": "feat: unify timeout= to a total budget (session and per-request)",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-14T13:23:30Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ecd06a18047d820ffafef8f69127aff61cb8b63d",
"body": "It was the only test in the default suite making a live third-party call\n(httpbin.org/headers), so an httpbin hiccup could fail the whole suite. Marked\n@pytest.mark.live + skipif(WAFER_LIVE != \"1\"), matching the reCAPTCHA live-test\nconvention. The default `pytest tests/` now has zero network dependencies; run\nthe live ones with WAFER_LIVE=1.",
"is_bot": false,
"headline": "test: gate the httpbin sec-ch-ua test behind @pytest.mark.live",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-14T12:59:31Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c2fb4af8375e238b2881d1c007aff14965cfca05",
"body": "Closes the SessionPool TODO loose end. The type stays unbuilt (correctly -\nflagged not-recommended); document the recipe instead. fetchaller reinvents an\nidentical lazy double-checked-locked singleton in 9+ site modules and its\ngeneric fetch spins a throwaway session per URL. Mistake #14 warned against\nrecreating sessions but never showed the reuse pattern - now it does: sync +\nasync lazy singleton, plus the host-keyed dict[host, session] variant for a\ngeneric fetcher hitting many hosts.",
"is_bot": false,
"headline": "docs: add session-reuse recipe to llms.txt (Mistake #14)",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-13T23:28:04Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "be66c9e38e368186fdcc87c47ab7f8b65ecfc959",
"body": "README.md was badly stale on the branch's new surface; filled the existing\nsections in place:\n- Response API: resp.cookies / resp.history / resp.emulation / get_cookie;\n resp.content is true wire bytes; charset-aware resp.text.\n- Session Configuration: attempt_timeout, fingerprint_pool, solve_origi\n[…]\n-> q=0.7 Accept value; xhr-jquery header details.\n\nllms.txt audited against the code - already accurate, left unchanged.\nVerified no em dashes, signatures match code, fences balanced. 1072 tests pass.",
"is_bot": false,
"headline": "docs: sync README + ref-docs to the new API",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-13T19:11:28Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f3fa04b846ef4696864603b2969fccad18d49736",
"body": "A 4-reviewer Opus pass (correctness/security/regression/architecture) over the\nfull branch surfaced these, now fixed:\n\n- max_response_size is enforced on EVERY transport, not just the wreq path. The\n native-TLS (Imperva) and Opera Mini paths now bound their wire read AND their\n decompressor, so a \n[…]\nts)\n instead of returning a dangling 3xx.\n- Docs: README documents mint_recaptcha_v3; llms.txt import block gains\n emulation_is_mobile; compute_co docstring corrected.\n\n1071 tests (+36), ruff clean.",
"is_bot": false,
"headline": "Address team code-review findings",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-13T14:13:17Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "de16f232614e4ae50847918def7dfde91706cfbc",
"body": "…-lite\n\nE9 - max_response_size= (session + per-request): caps the response body and\nraises ResponseTooLarge(url, size, limit). wreq streaming is used to abort early\nonce the cap is exceeded (the oversize body is never fully buffered); a\nContent-Length over the cap short-circuits before the read. Def\n[…]\nhost-matching (closing the Phase 1\nTODO: a Domain=co.uk cookie no longer over-matches a sibling). Reserved\nlocalhost is exempt. Degrades to TLD+1 on a miss.\n\n1035 tests (+63 over Phase 7), ruff clean.",
"is_bot": false,
"headline": "Phase 8: max_response_size, async solver entry, Shape tightening, PSL…",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-13T04:39:30Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "665d352c4b58904d064ec1575dbce8619a4293a1",
"body": "…iles\n\nE4 - embed=\"xhr-jquery\": like embed=\"xhr\" (fetch/CORS emulation) but adds\nX-Requested-With: XMLHttpRequest and the jQuery Accept (application/json,\ntext/javascript, */*; q=0.01) at the client level, for legacy $.ajax/XHR\nendpoints. Two consumers hand-rolled this. Plain xhr/iframe unchanged.\n\n\n[…]\n_envelope() reports\nis_mobile. wreq has no mobile Chromium profile, so no sec-ch-ua-mobile is\ninvented. Wire-verified SafariIos26_2 (iPhone UA, Safari JA4, no sec-ch-ua).\n\n972 tests (+21), ruff clean.",
"is_bot": false,
"headline": "Phase 7: jQuery-XHR embed mode, generalized solve_origin, mobile prof…",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-13T04:13:53Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3016510950b83e080e8f0353978716c574439558",
"body": "Add session.mint_recaptcha_v3(sitekey, action, *, origin=None, referer=None,\nv=None, enterprise=False) on SyncSession + AsyncSession - mints a v3 score token\nover pure HTTP via Google's anchor/reload endpoints using the session's own\nTLS-emulated client (no browser). Ported from bell-fibre-map's wor\n[…]\nfer mints the\ntoken, it can't guarantee the site's threshold passes. Distinct from the existing\nbrowser-based reCAPTCHA v2 grid solver.\n\n951 tests (+42), 1 live test gated on WAFER_LIVE=1, ruff clean.",
"is_bot": false,
"headline": "Phase 6: browser-free reCAPTCHA v3 token minting",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-13T03:49:47Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "67a5a575f11a1f150d4adc39909fc3b122e12d25",
"body": "…signal\n\n#2 - rotation now escalates ACROSS families before cycling versions. The ladder\nis Chrome -> Firefox -> Safari -> Edge -> Chrome-versions, and every family\nswitch swaps the matching header envelope (Phase 4's family_headers) so the TLS\nidentity and headers stay coherent (wire-verified each \n[…]\nrotation entry points (403, 429, empty-200, attempt-timeout) go through one\n_advance_rotation path so cross-family + pool + header coherence apply uniformly.\n\n909 tests (+19 over Phase 4), ruff clean.",
"is_bot": false,
"headline": "Phase 5: cross-family rotation ladder + fingerprint pool + empty-200 …",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-13T03:30:15Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e733224c0c97f2d25877b7a41d5e464b5648ade5",
"body": "…esp.emulation\n\n#1 - non-Chrome family support above the TLS line:\n- Classify any wreq Emulation into a family (chrome/edge/firefox/opera/safari),\n including FirefoxAndroid/FirefoxPrivate/SafariIos/SafariIPad variants.\n- Per-family HTTP header envelope when emulation= is set and headers= isn't:\n F\n[…]\nome_headers now always holds the true Chrome envelope so a rotated non-Chrome\nsession stays coherent. Wire-verified Firefox149 + Edge147 against tls.peet.ws.\n\n890 tests (+53 over Phase 3), ruff clean.",
"is_bot": false,
"headline": "Phase 4: family-aware fingerprints (Firefox/Edge), public envelope, r…",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-13T02:54:22Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "c7f143467c131944e038815abdf609cfe5f3422b",
"body": "Security:\n- Cookie files already land 0o600 via mkstemp; make that explicit (fchmod,\n POSIX-guarded) so the owner-only guarantee survives future refactors, and\n create the cache dir 0o700 so other local users can't enumerate which\n domains are cached (the files were already unreadable, the dir wa\n[…]\nme coverage that isn't there.\n- llms.txt: same per-type honesty + DataDome added to the browser-required\n list; note cookie files are 0o600 / cache dir 0o700.\n\n837 tests (+2 perms tests), ruff clean.",
"is_bot": false,
"headline": "Phase 3: harden cookie-cache perms + honest per-type solver-status docs",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-13T02:16:18Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ab20004e14c966252d3caf368d80d5e7f033c424",
"body": "E1 - split per-attempt timeout from the total deadline:\n- New attempt_timeout= (session default + per-request override), distinct\n from timeout=. Each attempt's wreq timeout is bounded by attempt_timeout\n (clamped to the remaining total budget when a per-request timeout deadline\n is also set). A \n[…]\nare always handed a\nsolver via browser_solver=, so a shared solver is no longer destroyed when\none session's context manager exits. Callers can use with/async with again.\n\n835 tests (+29), ruff clean.",
"is_bot": false,
"headline": "Phase 2: attempt_timeout (per-try bound) + solver-ownership lifecycle",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-13T02:04:06Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "9a3e0bfdc1724486b119d603f51c71fe941558d5",
"body": "… e.response)\n\nAdd requests/httpx-parity to WaferResponse and the challenge exceptions:\n\n- resp.text is now charset-aware: Content-Type charset -> <meta charset>\n sniff (HTML bodies only) -> utf-8. Decoding moved off wreq's text() onto\n the raw decompressed bytes (resp.bytes()), so resp.content is\n[…]\nt() return individual Set-Cookie values\n(5-tuple) so multi-cookie responses aren't collapsed; also fixes an Opera\nMini duplicate-header last-wins overwrite.\n\n806 tests (+72 over baseline), ruff clean.",
"is_bot": false,
"headline": "Phase 1: response & exception parity (charset text, cookies, history,…",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-13T01:37:50Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3f490c047317d6182f412f5dda27138a73db3ef8",
"body": "… host\n\nThe browser challenge-solver navigated top-level straight to an API host\n(e.g. api2.realtor.ca), which Imperva answers with its interactive\n\"Error 15\" block - a request shape no real browser produces. wait_for_imperva\nthen polled forever for a cookie that a top-level API nav never sets, so t\n[…]\ne on the derived embedder; skip IP hosts\n\nVerified live through fetchaller's realtor flow (geocode + search, GET + POST)\nand reviewed by correctness/regression/architecture/security agents. 734 tests.",
"is_bot": false,
"headline": "Fix Imperva \"Error 15\": browser-solve on the origin page, not the API…",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-07T19:59:18Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "93a11d4f6c9a57ad421ed9ecb281a39f3dbc0d39",
"body": "Clears the \"Node.js 20 actions are deprecated\" warning on the v4.2.2 pin.\nv6.0.3 runs on node24. Updated the SHA pin in ci.yml and both publish.yml jobs.",
"is_bot": false,
"headline": "ci: bump actions/checkout to v6.0.3 (Node 24)",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-07T15:51:43Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c63f556b48ba5cf3be19548acfd4c83024f4ea8d",
"body": "Now that Imperva is fully solved (native-TLS no-browser bypass for light usage,\nbrowser-solve reese84 for heavy usage), bring all docs in line:\n\n- README.md: new \"Imperva / Incapsula (no-browser bypass)\" section, updated the\n challenge-escalation steps, added _native_tls.py to the file layout.\n- ll\n[…]\nst.md: api2.realtor.ca entry now covers light (12/12 no-browser)\n + heavy (18/18 browser-solve) and the http.client transport.\n- todo-realtorsolve.md: heavy usage is solved, no longer an open caveat.",
"is_bot": false,
"headline": "docs: document the complete Imperva solution",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-07T15:01:11Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "e344f3ffe810318a117512db0e0c2ae190c49d78",
"body": "Fix C (commit 9961237) made a *pinned* host go straight to the browser solve\non the heavy reese84 state, but the *unpinned* trigger path -the common case-\nstill fell through and burned fingerprint rotations (Safari->Chrome, all\nBoringSSL and all re-challenged, plus session-retirement noise) before r\n[…]\nwser solve firing with no preceding\n\"Rotation: switched\"/\"Session retired\" log line (vs the rotation that showed up\nbefore this fix). Test: test_async_trigger_native_fail_reaches_browser_not_rotation.",
"is_bot": false,
"headline": "Skip pointless rotations on the unpinned Imperva path too",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-07T14:33:43Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "99612372f494da8f38b4873f9bb72462f2e20313",
"body": "Correctness:\n- Skip the native path for socks/https proxies (it can't CONNECT-tunnel them):\n new _native_tls_usable() gates the trigger, so those sessions go straight to\n the proxy-aware wreq path instead of wasting 4 native attempts then failing.\n- Reset native_attempted/native_retries on a cross\n[…]\n+ docs/ref-imperva.md (skip, not\n raise-then-fall-back).\n- Stripped em dashes from todo-realtorsolve.md / todo-wellfoundsolve.md.\n- Commented the was_retried=True and no-browser-exhaustion contracts.",
"is_bot": false,
"headline": "Address second-round self-review findings (3 reviewers)",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-07T14:17:17Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "f492c3ba74075385914ec0af544c40d5f1ebed47",
"body": "Under heavy load Imperva revokes the OpenSSL free pass and demands the reese84\nJS token from everyone. The unpinned path already escalated to the browser\nsolve (which earns reese84; wreq then carries it through, verified live 18/18).\nBut a host pinned to the native path would exhaust its native retr\n[…]\nbrowser path\n- tests: test_async_sticky_exhausted_falls_back_to_browser_path (+ the existing\n no-browser exhaustion test still raises)\n- llms.txt / docs/ref-imperva.md: corrected heavy-usage behavior",
"is_bot": false,
"headline": "Bulletproof Imperva heavy-usage: pinned host falls back to browser solve",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-07T13:53:54Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ceb2bd759859982d7e03c3f1c171c119ffd0889c",
"body": "Correctness + consistency fixes from a two-reviewer self-review (no behavior\nchange for the realtor happy path; verified live 200 + 714 tests green):\n\n- Trigger success now calls rate_limiter.record(domain), matching the sticky\n path (was skipped, so spacing wasn't enforced before the next native c\n[…]\na\n pinned host's retries; document the proxy behavior.\n- Add docs/ref-imperva.md (one ref doc per WAF type, per CLAUDE.md).\n\nAsync and sync native blocks verified byte-identical (modulo await/sleep).",
"is_bot": false,
"headline": "Address self-review findings on native-TLS Imperva fallback",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-07T03:15:26Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "5e31f5d4ba4b73ac471ccaf4ba16b17ef3b8c534",
"body": "Firsthand during the full-review pass: appdev.pwc.com now returns the\nIncapsula JS interstitial (200, ~3.3KB with _Incapsula_Resource), correctly\ndetected as imperva by the 0.2.2 200-interstitial logic. curl gets the same\nchallenge page, so the OpenSSL native fallback correctly does not pin it and\nfalls through to browser-solve. Not a regression from the native-TLS change.",
"is_bot": false,
"headline": "site-list: appdev.pwc.com now serves Imperva interstitial (was TLS pass)",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-07T02:36:31Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a66e4cb3c916c864f90fd4fcad4c063f609618ee",
"body": "Verified firsthand 2/2 live that wafer returns the real SSR document for all\nfour wellfound page types: /jobs passes no-browser; /role, /company, /jobs/{id}\nhit white-labeled DataDome (ddm.wellfound.com) and pass via the existing browser\nsolver's passive passthrough. No code change needed.\n\nRecords \n[…]\ngested -those scripts are on every wellfound page\nincluding the successful SSR /jobs 200, so it would false-positive into an\ninfinite solve loop (same class as the Imperva _Incapsula_Resource marker).",
"is_bot": false,
"headline": "Document wellfound.com: already solved by existing DataDome solver",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-07T01:28:00Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "a78ee6f16ac3485457e5747521afa88f44b38864",
"body": "api2.realtor.ca fingerprints the TLS stack itself: every wreq/BoringSSL\nprofile (Chrome/Safari/OkHttp, H1/H2) is challenged regardless of cookies,\nwhile a generic OpenSSL client sending the minimal header set (no Sec-Fetch-*,\nno Accept-Language/Encoding) gets a free pass. wreq can't produce an OpenS\n[…]\nicky routing\n- wafer/_fingerprint.py: host_user_agent() for the native path\n- tests/test_native_tls.py: 18 tests; conftest wiring\n- llms.txt, docs/site-list.md, todo-realtorsolve.md: docs + resolution",
"is_bot": false,
"headline": "Add native-TLS (OpenSSL) fallback for Imperva TLS-fingerprinting sites",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-07T00:24:50Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "94366001b4a45eb22a6aba74fe78d19019231cf0",
"body": "…olve timeout\n\nwreq 0.11.3 -> 0.12.0. The only Python-API change is ResolverOptions ->\nDnsOptions, which wafer does not use. Chrome147 is still the newest\nPython-exposed Emulation profile (Chrome148 exists only at the Rust\nlevel), so DEFAULT_EMULATION is unchanged. Wire-verified post-bump:\nChrome/Sa\n[…]\nitive guard) and for solve-timeout clamping (sync + async +\nlock-busy). Docs: site-list.md (realtor.ca, wellfound), llms.txt (timeout\n/ solver concurrency), README/CLAUDE.md/ref-wreq.md version notes.",
"is_bot": false,
"headline": "Bump wreq to 0.12.0; detect Imperva 200 interstitial; bound browser-s…",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-06-06T20:50:18Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "550de0a149af93a181a1d0f56fd4efa621c2c3e3",
"body": "Upstream wreq 0.11.3 ships the KeyShare registration fix (PR #582) that\nblocked us on 0.11. This bump adopts the v0.11 API renames:\n\n- Client kwarg: verify -> tls_verify (silently dropped pre-rename;\n badssl confirmed our CertStore would have been a no-op)\n- TlsOptions: key_shares_limit=int -> key_\n[…]\nested vs\nnowsecure.nl (CF max-security) -200 on first try, no challenge.\n\nDocs note the Client-level silent-acceptance footgun (extends prior\nTlsOptions/Http2Options note) and the repr() shape change.",
"is_bot": false,
"headline": "Bump wreq to 0.11.3, default to Chrome147",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-05-11T14:20:03Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "46eb339b8948f0ca4c0cb7a7e5223eab860ae51a",
"body": "Patchright 1.58.0 -> 1.59.1: Chromium 147, stabilized init script\ninjection, upstream Playwright bug fixes. Other lockfile bumps:\nonnxruntime 1.24.2 -> 1.25.1, pillow 12.1.1 -> 12.2.0,\nhuggingface_hub 1.4.1 -> 1.13.0, ruff 0.15.1 -> 0.15.12,\npytest 9.0.2 -> 9.0.3, datasets 4.8.4 -> 4.8.5.\n\nwreq held at <0.11 pending upstream KeyShare fix\n(merged in PR #582, awaiting next PyPI release).",
"is_bot": false,
"headline": "Bump patchright to 1.59.1, refresh dep lockfile",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-05-03T16:25:44Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "67a48c331f4b9da0c4f6b5df0d198cb2a7437864",
"body": null,
"is_bot": false,
"headline": "Gitignore Claude session state directory",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-05-03T16:25:38Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4ab7a411cb56bdaeccdcc935db28a7439ea972d6",
"body": "- Dependency: rnet>=3.0.0rc22,<4 -> wreq>=0.10.2,<0.11\n- All imports: from rnet -> from wreq across 12 source + 6 test files\n- Rename docs/ref-rnet.md -> docs/ref-wreq.md\n- Update llms.txt, README.md, CLAUDE.md references\n- Add migration notice for users upgrading from rnet\n- Tighten version pin to <0.11 (pre-1.0 semver caution)",
"is_bot": false,
"headline": "Migrate from rnet to wreq (renamed upstream)",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-04-05T15:43:41Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fb1680e53a972311c97573bc31aac78036e87a5d",
"body": "Wire-verified identical to real Dart SDK 3.11.4 (JA3 hash\n203503b7023848ab87b9836c336b8e81). HTTP/1.1 forced via\nalpn_protocols=[] in TlsOptions, not http1_only (which injects\nan ALPN extension). First published Dart/Flutter TLS profile\nin any impersonation library.",
"is_bot": false,
"headline": "Add Dart 3.11 TLS profile for Flutter/Dart app impersonation",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-03-28T17:05:53Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "998e8129b30a08ce89ed5af5a84afe4992bc1f72",
"body": "- Migrate DET annotations to HF-compatible metadata.jsonl (file_name field with subdir prefix)\n- Upload all training data to two private HF repos as Parquet (labeled + unlabeled)\n- Add dataset cards and upload runbook (training/recaptcha/huggingface-upload.md)\n- Add frozen dataset hash caching (.has\n[…]\n(10-16h) instead of fixed schedule\n- Use cached phash from metadata when available, skip redundant PIL open\n- Deduplicate CLAUDE.md rules already in global config\n- Add datasets and Pillow to dev deps",
"is_bot": false,
"headline": "Add HuggingFace dataset backup, improve collector dedup caching",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-03-27T21:19:17Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "a8faaee88605a2b094d58411999641b4862a63af",
"body": "… block detection\n\n- Remove --disable-site-isolation-trials flags (CF Turnstile detects and refuses to resolve)\n- Rewrite CF solver: _page_is_challenge() helper, 5s click throttle, managed+interactive support\n- Add patch_frame_screenxy() for per-frame CDP screenXY fix (DD, CF, hCaptcha, reCAPTCHA, B\n[…]\narkers to passthrough filters, expand search range to [:10000]\n- Detect F5 Shape soft-block pages (siteclosed/invitation redirect)\n- Add researchgate, chewy search/product to smoke tests and site list",
"is_bot": false,
"headline": "Fix CF Turnstile solver, per-frame screenXY/headless injection, Shape…",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-03-06T17:30:48Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "3916971e110a60411219fb3cdf6be008fd905a68",
"body": "- Skip _HEADLESS_FIX_SCRIPT for Akamai (behavioral JS detects toString wrapper)\n- Add Akamai behavioral challenge auto-resolve detection (page content growth)\n- Reduce Kasada settle time 10s->3s (CT/ST arrive in 2-3s, rest was waste)\n- Remove DD audio/slider/slide-right solvers (DD rejects correct answers via CDP input detection)\n- Add early bail-out when DD escalates beyond WASM PoW\n- Add docs/ref-datadome.md documenting what works vs what doesn't",
"is_bot": false,
"headline": "Fix headless Chewy solve, remove broken DD interactive solvers",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-03-05T21:26:41Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "e9ceee17807e4f8ebe5de646c1a6d3a42f4caf86",
"body": null,
"is_bot": false,
"headline": "Move collector to training/recaptcha/, fix dedup threading bugs",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-03-04T16:16:50Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1650e75c0e19abc0d8e2e3ea464a4bd74de73731",
"body": "…rprint pinning\n\nDataDome: audio captcha solver using faster-whisper (tiny/int8). Transcribes\n6 spoken digits, preferred over slider when available. Added faster-whisper\nto [browser] extra.\n\nKasada: fix headless detection by skipping _HEADLESS_FIX_SCRIPT (ips.js\ndetects Function.prototype.toString w\n[…]\nes from being\nsent with a different identity after rotation.\n\nHeadless: add scrgb-linear to launch args, conditional init script skip per\nchallenge type, new ref-headless.md documenting all overrides.",
"is_bot": false,
"headline": "Add DD audio captcha solver, fix headless Kasada detection, fix finge…",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-03-04T13:44:42Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "4d77cae8c60026d7e8285a32d5068121e8509cb7",
"body": "Kasada (and other WAFs) instantly reject browsers with \"HeadlessChrome\"\nin the user-agent. Probe the raw UA at launch and replace it with\n\"Chrome\" so every headless context passes WAF fingerprinting.",
"is_bot": false,
"headline": "Fix headless browser leaking HeadlessChrome in UA string",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-03-02T20:31:57Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f257763702abbc63640b7c1bd333de849abb0848",
"body": "… refs\n\n- llms.txt: Replace verbose Kasada/reCAPTCHA sections with generic\n passthrough note, update DataDome solver list, fix result.extras comment\n- README: Fix challenge count (16->17, add GeeTest), fix max_rotations\n default (1->2), fix kwargs list (data->body), add DD slide-right\n- ref-kasada\n[…]\nh \"next step\" (ST capture already done, blocker is H HMAC),\n update Integration status re: disabled CT+CD injection\n- site-list.md: Add DD slide-right to description+summary, fix stale\n Twitch entry",
"is_bot": false,
"headline": "Update docs for v0.1.6: Kasada passthrough, DD slide-right, fix stale…",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-03-02T16:22:45Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "c4e86c96bb400822c87214b234daf846d69184a2",
"body": "…ookie TTL\n\n- Rewrite generate_cd() with correct hash chaining (challenge_id, sequential nonces, chain between subchallenges)\n- Disable CT+CD header injection (requires H HMAC; sending without H causes server rejection)\n- Add Kasada passthrough for dual-WAF sites where cookie replay fails (Chewy: Ak\n[…]\nl-WAF)\n- Add DataDome slide-right challenge solver (new \"slide right to secure\" variant, no canvas)\n- Fix browser-solve session cookies getting dropped (expires=-1 → 0.0 → cache eviction; now 24h TTL)",
"is_bot": false,
"headline": "Rewrite Kasada CD algorithm, add DD slide-right solver, fix session c…",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-03-02T15:54:34Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "012e1a05b766e854284222fb503e91fee58266db",
"body": "- Add training/recaptcha/ scripts: train_mps.py, export.py, dedup.py, predict_cls.py, collect.py\n- Update Mousse reviewer UI (recorder, styles, server, static assets)\n- Update reCAPTCHA grid solver and ref-models docs for new dataset layout\n- Move training data gitignore rules to nested training/recaptcha/.gitignore",
"is_bot": false,
"headline": "Add training scripts, update Mousse UI and reCAPTCHA grid solver",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-03-01T03:47:52Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "a4cfb069e0420d9751b3a07adabcd6d124f907ec",
"body": "…n up errors and Mousse UI\n\n- reCAPTCHA grid solver: swap YOLO for EfficientNet-B0 (3x3 CLS) + D-FINE (4x4 DET) via HuggingFace ONNX\n- Cookie cache: replace fcntl file locks with threading locks and atomic temp-file writes\n- Remove SessionBlocked error class, add WaferHTTPError\n- Mousse: add DET/CLS\n[…]\nA training data\n- Add docs/ref-models.md and docs/ref-recaptcha.md\n- Delete wafer/browser/models/__init__.py (models now downloaded from HuggingFace)\n- Update README, llms.txt, and pyproject.toml deps",
"is_bot": false,
"headline": "Replace YOLO with EfficientNet+D-FINE, fix cookie cache locking, clea…",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-02-27T18:14:27Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "6143d5423caa91cd1bb453e07864beb6b4f87b80",
"body": "Challenge detection, cookie cache poisoning, solver dispatch parity,\nbrowser solver error handling, Imperva reese84, Opera Mini isolation,\nfingerprint build numbers, embed header duplication. Added tests.",
"is_bot": false,
"headline": "Fix bugs found during full codebase audit",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-02-26T03:16:39Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "aef1c14204cd46374f4e7d6b429a6127fb43f5e0",
"body": "- Remove response cookie write-through (was poisoning fresh TLS sessions\n with stale WAF-bound cookies)\n- Add fresh-session-first rotation: 403 now rebuilds TLS before switching\n to Safari, clearing domain cookies to avoid rehydrating tainted ones\n- Bump max_rotations default 1 -> 2 to budget fres\n[…]\nhen patchright is not installed\n- Fix embed mode: Sec-Fetch-Site computed dynamically, Accept set at\n client level to avoid HTTP/2 duplication\n- Update tests, README, llms.txt, and ref-sec-fetch docs",
"is_bot": false,
"headline": "Fix cookie cache poisoning, rotation strategy, and BrowserSolver import",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-02-25T14:33:24Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "0de8f830e2d20c01b8ac1f81658a0109d44b79ac",
"body": "- Remove reCAPTCHA/hCaptcha body detection on HTTP 200 (false positives\n on pages with login forms like old.reddit.com)\n- Rotation fallback switches Chrome to Safari instead of cycling Chrome\n versions (fundamentally different TLS/H2 fingerprint)\n- max_rotations default 10 -> 1 (one rotation attempt, then give up)\n- Rotation delay = rate limiter interval + 1s (replaces aggressive 0.5s\n exponential backoff that hammered sites)",
"is_bot": false,
"headline": "Fix false-positive challenge detection, add Safari rotation fallback",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-02-24T20:18:51Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6233cde19f76f2f55186a57002fba49dadcf305a",
"body": "…ixes\n\n- Replace audio-based reCAPTCHA solver with image grid solver (3x3 classification + 4x4 COCO detection); gracefully skips when ONNX models absent\n- Add 45 recorded grid mouse hop paths for natural cell navigation\n- Add Mousse grid-specific short-hop recording mode\n- Add llms.txt consumer impl\n[…]\nnce docs\n- Fix cookie management, challenge detection, and async/sync response wrappers\n- Update WAF reference docs (Baxia, GeeTest, Kasada, PX, rnet)\n- Update site list with latest smoke test results",
"is_bot": false,
"headline": "Add reCAPTCHA image grid solver, Mousse recorder improvements, core f…",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-02-24T17:53:52Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "b488416f7644b43d74750738499a92ea9f1eb10e",
"body": "hatch-vcs saw untracked artifacts from install/test steps, producing\na local version (0.1.1.dev0+g...) that PyPI rejects. Publish job now\ngets its own pristine checkout.",
"is_bot": false,
"headline": "Fix publish: split into test + publish jobs to avoid dirty tree",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-02-23T23:30:40Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1b57f60dbb6c11620d57b299389b2ee6ceb0023f",
"body": null,
"is_bot": false,
"headline": "Fix publish: enable fetch-tags for hatch-vcs version derivation",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-02-23T23:20:06Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4191fc0335327dda17cd8375e85117b1a6dacd0e",
"body": "…workflows",
"is_bot": false,
"headline": "Fix publish: use version tag for Docker-based pypi-publish, align CI …",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-02-23T23:07:13Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "cbb812759964c58a10bfd0a0cd1fcdfd5e6c2b71",
"body": null,
"is_bot": false,
"headline": "Fix CI: pin actions, install browser extra, run all tests",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-02-23T22:08:26Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "4b79008f42dfc5f52bea5603b6412e590ee765b2",
"body": null,
"is_bot": false,
"headline": "Harden PyPI packaging: pin CI actions, add py.typed, cap rnet dep",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-02-23T21:08:08Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "014c61fb141c6c2a8b9512a9cc524ab133820d43",
"body": "…r, JS-only fast-fail\n\n- Safari 26 M3/M4 profile (custom TlsOptions + Http2Options, safari_locale param)\n- hCaptcha checkbox and reCAPTCHA v2 checkbox browser solvers\n- DataDome puzzle slider solver (CV notch detection + mousse drag replay)\n- JS-only challenges fast-fail without browser solver inste\n[…]\nename solver docs to docs/ref-*.md, add docs/ref-rnet.md with full API gotchas\n- Trim CLAUDE.md, update README with Safari docs and new challenge types\n- Add audio optional dependency (faster-whisper)",
"is_bot": false,
"headline": "Add Safari profile, hCaptcha/reCAPTCHA solvers, DataDome puzzle slide…",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-02-23T19:25:03Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "8a85ee219ac1bd8c72cdd520bf03eb045cd3fd5a",
"body": "- Replace live httpbin.org session tests with mocked rnet tests (no network in CI)\n- Install .[dev,browser] in CI so test_cv.py can import cv2\n- Remove --ignore flags from pytest command\n- Fix cookie cache load() to prune expired entries from disk instead of leaving them",
"is_bot": false,
"headline": "Fix CI: mock session tests, install browser extra, prune expired cookies",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-02-23T03:21:53Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "1b52273e382c3e0a872cfe8ed959297b2329a2eb",
"body": "- GeeTest v4 slide CAPTCHA solver (CV notch detection + drag replay, 12/12 on demo)\n- Baxia/AliExpress NoCaptcha slider solver (stealth injection, TMD flow, slide replay)\n- Opera Mini profile: stdlib urllib transport, no rnet — for Google/DDG SSR results\n- Public API: export all errors, Profile, DEF\n[…]\necompression\n- GeeTest detection: size guard against false positives on large pages\n- Cookie cache: auto-sweep expired domain files\n- Docs: press-and-hold.md → perimeterx.md, add baxia.md + geetest.md",
"is_bot": false,
"headline": "Add GeeTest, Baxia, and Opera Mini solvers; harden public API",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-02-22T23:29:41Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "fbc78a592b62b53ee8a46a7a9f7420b9693d64b8",
"body": null,
"is_bot": false,
"headline": "Fix CI: create venv before installing deps",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-02-22T04:23:03Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "c33db1bbc338d582a728f76b39025944a66c58d3",
"body": "Anti-detection HTTP client wrapping rnet with TLS fingerprinting,\nWAF challenge detection/solving (14 types), cookie caching, retry\nwith rotation, rate limiting, embed mode, and browser solving.",
"is_bot": false,
"headline": "Initial release",
"author_name": "Avery Levitt",
"author_login": "Averyy",
"committed_at": "2026-02-22T04:21:47Z",
"body_truncated": false,
"is_coding_agent": false
}
],
"releases_count": 24,
"commits_last_year": 68,
"latest_release_at": "2026-07-29T22:45:02Z",
"latest_release_tag": "v0.4.3",
"releases_from_tags": true,
"days_since_last_push": 0,
"active_weeks_last_year": 12,
"days_since_latest_release": 0,
"mean_days_between_releases": 5.8
},
"community": {
"has_readme": true,
"has_license": true,
"has_description": true,
"has_contributing": false,
"health_percentage": 42,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"ecosystem": {
"packages": [
{
"name": "wafer-py",
"exists": true,
"license": "Apache-2.0",
"keywords": [
"anti-detection",
"client",
"fingerprint",
"http",
"scraping",
"tls",
"waf",
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Internet :: WWW/HTTP"
],
"ecosystem": "pypi",
"matches_repo": true,
"registry_url": "https://pypi.org/project/wafer-py/",
"is_deprecated": false,
"latest_version": "0.4.3",
"repository_url": "https://github.com/Averyy/wafer",
"versions_count": 25,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": null,
"monthly_downloads": null,
"first_published_at": "2026-02-19T18:46:56.363731Z",
"latest_published_at": "2026-07-29T22:46:58.891785Z",
"latest_version_yanked": null,
"days_since_latest_publish": 0
}
]
},
"popularity": {
"forks": 1,
"stars": 5,
"watchers": 0,
"fork_history": {
"days": [
{
"date": "2026-06-05",
"count": 1
}
],
"complete": true,
"collected": 1,
"total_forks": 1
},
"star_history": null,
"open_issues_and_prs": 2
},
"ai_readiness": {
"has_nix": false,
"example_dirs": [],
"has_llms_txt": true,
"has_dockerfile": false,
"has_mcp_signal": false,
"bootstrap_files": [],
"api_schema_files": [],
"has_devcontainer": false,
"typecheck_configs": [
"wafer/py.typed"
],
"toolchain_manifests": [],
"largest_source_bytes": 395436,
"source_files_sampled": 97,
"oversized_source_files": 8,
"agent_instruction_files": [
"CLAUDE.md"
],
"agent_instruction_max_bytes": 6635
},
"dependencies": {
"manifests": [
"pyproject.toml"
],
"advisories": {
"error": null,
"scope": null,
"source": null,
"findings": [],
"collected": false,
"malicious": [],
"truncated": false,
"by_severity": {},
"advisory_count": 0,
"affected_count": 0,
"assessed_count": 0,
"malicious_count": 0,
"assessed_package": null,
"unassessed_count": 0,
"direct_affected_count": 0
},
"ecosystems": [
"pypi"
],
"dependencies": [
{
"name": "wreq",
"manifest": "pyproject.toml",
"ecosystem": "pypi",
"version_constraint": ">=0.12.1,<0.13"
}
],
"all_dependencies": {
"error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
"source": null,
"packages": [],
"collected": false,
"truncated": false,
"total_count": null,
"direct_count": null,
"indirect_count": null
}
},
"maintainership": {
"issues": {
"open_prs": 0,
"merged_prs": 0,
"open_issues": 2,
"closed_ratio": 0.333,
"closed_issues": 1,
"closed_unmerged_prs": 0
},
"bus_factor": 1,
"bot_contributors": 0,
"top_contributors": [
{
"type": "User",
"login": "Averyy",
"commits": 71,
"avatar_url": "https://avatars.githubusercontent.com/u/3880328?v=4"
}
],
"contributors_sampled": 1,
"top_contributor_share": 1
},
"quality_signals": {
"has_ci": true,
"has_tests": true,
"ci_workflows": [
"ci.yml",
"publish.yml",
"training.yml"
],
"has_docs_dir": true,
"linter_configs": [],
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [
"uv.lock"
],
"scorecard": {
"checks": [
{
"name": "Binary-Artifacts",
"score": 10,
"reason": "no binaries found in the repo",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
},
{
"name": "Branch-Protection",
"score": 0,
"reason": "branch protection not enabled on development/release branches",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": null,
"reason": "no pull request found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
},
{
"name": "CII-Best-Practices",
"score": 0,
"reason": "no effort to earn an OpenSSF best practices badge detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
},
{
"name": "Code-Review",
"score": 0,
"reason": "Found 0/30 approved changesets -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
},
{
"name": "Contributors",
"score": 0,
"reason": "project has 0 contributing companies or organizations -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
},
{
"name": "Dangerous-Workflow",
"score": 10,
"reason": "no dangerous workflow patterns detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
},
{
"name": "Dependency-Update-Tool",
"score": 0,
"reason": "no update tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
},
{
"name": "Fuzzing",
"score": 0,
"reason": "project is not fuzzed",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
},
{
"name": "License",
"score": 10,
"reason": "license file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
},
{
"name": "Maintained",
"score": 10,
"reason": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
},
{
"name": "Packaging",
"score": 10,
"reason": "packaging workflow detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": 10,
"reason": "all dependencies are pinned",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
},
{
"name": "SAST",
"score": 0,
"reason": "no SAST tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
},
{
"name": "Security-Policy",
"score": 0,
"reason": "security policy file not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": null,
"reason": "no releases found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
},
{
"name": "Token-Permissions",
"score": 0,
"reason": "detected GitHub workflow tokens with excessive permissions",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 0,
"reason": "51 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "b673126e7b5ff33c7e6fb76bbc993610750b92d0",
"ran_at": "2026-07-29T22:48:24Z",
"aggregate_score": 3.9,
"scorecard_version": "v5.5.0"
},
"has_codeql_workflow": false,
"has_security_policy": false,
"has_dependabot_config": false
},
"contribution_flow": {
"collected": true,
"ci_last_run_at": "2026-07-29T22:47:02Z",
"oldest_open_prs": [],
"last_merged_pr_at": null,
"ci_last_conclusion": "SUCCESS",
"oldest_open_issues": [
{
"number": 1,
"created_at": "2026-06-05T04:09:17Z",
"last_comment_at": "2026-06-05T05:30:28Z",
"last_comment_author": "shauneccles"
},
{
"number": 3,
"created_at": "2026-06-05T05:29:59Z",
"last_comment_at": null,
"last_comment_author": null
}
]
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/Averyy/wafer",
"host": "github.com",
"name": "wafer",
"owner": "Averyy"
},
"metrics": {
"overall": {
"key": "overall",
"band": "moderate",
"name": "Overall health",
"note": null,
"notes": [],
"value": 51,
"inputs": {
"security": 39,
"vitality": 78,
"community": 29,
"governance": 41,
"engineering": 62
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "good",
"name": "Vitality",
"value": 78,
"weight": 0.22,
"metrics": [
{
"key": "development_activity",
"band": "good",
"name": "Development activity",
"note": null,
"notes": [],
"value": 71,
"inputs": {
"commits_last_year": 68,
"human_commit_share": 1,
"days_since_last_push": 0,
"active_weeks_last_year": 12
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 0 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "push_recency",
"params": {
"days": 0
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "12/52 weeks with commits",
"points": 8.3,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 12
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "68 commits in the last year",
"points": 16.5,
"status": "partial",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 68
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "excellent",
"name": "Release discipline",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 88,
"inputs": {
"releases_count": 24,
"latest_release_tag": "v0.4.3",
"releases_from_tags": true,
"days_since_latest_release": 0,
"mean_days_between_releases": 5.8
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "24 version tags (no GitHub releases)",
"points": 16.2,
"status": "partial",
"details": [
{
"code": "version_tags_no_releases",
"params": {
"count": 24
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 0 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 0
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "a release every ~5.8 days",
"points": 27,
"status": "met",
"details": [
{
"code": "release_cadence",
"params": {
"gap": 5.8
}
}
],
"max_points": 27
},
{
"key": "openssf_scorecard_signed_releases",
"name": "OpenSSF Scorecard: Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 10
}
]
},
{
"key": "abandonment",
"band": "excellent",
"name": "Abandonment",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"cap": null,
"state": "unverified",
"guards": [],
"signals": [],
"red_flag": false,
"multiplier_pct": 100,
"declared_reason": null,
"unverified_reason": "repository_too_young",
"unanswered_open_prs": null,
"unanswered_open_issues": null,
"days_since_last_merged_pr": null,
"days_since_last_human_commit": null,
"days_since_last_human_commit_is_floor": false
},
"components": [
{
"key": "project_is_still_maintained",
"name": "Project is still maintained",
"detail": "maintenance record not established from the collected data",
"points": 100,
"status": "met",
"details": [
{
"code": "abandonment_unverified",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Is the project alive — is code being written and are releases shipping?"
},
{
"key": "community",
"band": "critical",
"name": "Community & Adoption",
"value": 29,
"weight": 0.18,
"metrics": [
{
"key": "popularity",
"band": "critical",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 10,
"inputs": {
"forks": 1,
"stars": 5,
"watchers": 0,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "5 stars",
"points": 9.8,
"status": "partial",
"details": [
{
"code": "stars",
"params": {
"count": 5
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "1 forks",
"points": 0,
"status": "missed",
"details": [
{
"code": "forks",
"params": {
"count": 1
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "0 watchers",
"points": 0,
"status": "missed",
"details": [
{
"code": "watchers",
"params": {
"count": 0
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "moderate",
"name": "Community health",
"note": null,
"notes": [],
"value": 50,
"inputs": {
"has_readme": true,
"has_license": true,
"has_contributing": false,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 22.5,
"status": "met",
"details": [],
"max_points": 22.5
},
{
"key": "license",
"name": "License",
"detail": "recognized license (Apache-2.0)",
"points": 22.5,
"status": "met",
"details": [
{
"code": "license_standard",
"params": {}
},
{
"code": "license_spdx",
"params": {
"spdx": "Apache-2.0"
}
}
],
"max_points": 22.5
},
{
"key": "contributing_guide",
"name": "CONTRIBUTING guide",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 18
},
{
"key": "code_of_conduct",
"name": "Code of conduct",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 13.5
},
{
"key": "issue_template",
"name": "Issue template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.2
},
{
"key": "pr_template",
"name": "PR template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.3
}
]
}
],
"description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
},
{
"key": "governance",
"band": "at_risk",
"name": "Sustainability & Governance",
"value": 41,
"weight": 0.24,
"metrics": [
{
"key": "maintainer_resilience",
"band": "critical",
"name": "Maintainer resilience (bus factor)",
"note": null,
"notes": [],
"value": 10,
"inputs": {
"bus_factor": 1,
"contributors_sampled": 1,
"top_contributor_share": 1
},
"components": [
{
"key": "bus_factor",
"name": "Bus factor",
"detail": "1 contributor(s) cover half of all commits",
"points": 9,
"status": "partial",
"details": [
{
"code": "bus_factor",
"params": {
"count": 1
}
}
],
"max_points": 54
},
{
"key": "commit_distribution",
"name": "Commit distribution",
"detail": "top contributor authored 100% of commits",
"points": 0,
"status": "missed",
"details": [
{
"code": "top_contributor_share",
"params": {
"share": 100
}
}
],
"max_points": 22.5
},
{
"key": "contributor_breadth",
"name": "Contributor breadth",
"detail": "1 contributors",
"points": 1.4,
"status": "partial",
"details": [
{
"code": "contributors_sampled",
"params": {
"count": 1
}
}
],
"max_points": 13.5
},
{
"key": "openssf_scorecard_contributors",
"name": "OpenSSF Scorecard: Contributors",
"detail": "project has 0 contributing companies or organizations -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "responsiveness",
"band": "critical",
"name": "Issue & PR responsiveness",
"note": "Excluded from scoring (no data or not applicable): PR acceptance. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"pr_acceptance"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 25,
"inputs": {
"merged_prs": 0,
"open_issues": 2,
"closed_issues": 1,
"issue_closed_ratio": 0.333,
"closed_unmerged_prs": 0
},
"components": [
{
"key": "issue_resolution",
"name": "Issue resolution",
"detail": "33% of issues closed",
"points": 15.6,
"status": "partial",
"details": [
{
"code": "issues_closed_share",
"params": {
"share": 33
}
}
],
"max_points": 46.75
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "no decided pull requests or no data",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_decided_prs_or_data",
"params": {}
}
],
"max_points": 38.25
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
}
]
},
{
"key": "stewardship",
"band": "at_risk",
"name": "Ownership & stewardship",
"note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"verified_domain"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 47,
"inputs": {
"followers": 9,
"owner_type": "User",
"is_verified": null,
"owner_login": "Averyy",
"public_repos": 13,
"account_age_days": 4883
},
"components": [
{
"key": "ownership_backing",
"name": "Ownership backing",
"detail": "personal (user) account",
"points": 10,
"status": "partial",
"details": [
{
"code": "owner_personal",
"params": {}
}
],
"max_points": 30
},
{
"key": "verified_domain",
"name": "Verified domain",
"detail": "not applicable to user accounts",
"points": 0,
"status": "excluded",
"details": [
{
"code": "not_applicable_to_user_accounts",
"params": {}
}
],
"max_points": 20
},
{
"key": "owner_reach",
"name": "Owner reach",
"detail": "9 followers of Averyy",
"points": 7.2,
"status": "partial",
"details": [
{
"code": "owner_followers",
"params": {
"count": 9,
"login": "Averyy"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "13 public repos, account ~13 yr old",
"points": 20.3,
"status": "partial",
"details": [
{
"code": "public_repos",
"params": {
"count": 13
}
},
{
"code": "account_age_years",
"params": {
"years": 13
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "excellent",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"packages": [
"wafer-py"
],
"ecosystems": "pypi",
"any_deprecated": false,
"min_days_since_publish": 0
},
"components": [
{
"key": "published_resolvable",
"name": "Published & resolvable",
"detail": "1 package(s) on pypi",
"points": 25,
"status": "met",
"details": [
{
"code": "packages_published",
"params": {
"count": 1,
"ecosystems": "pypi"
}
}
],
"max_points": 25
},
{
"key": "publish_recency",
"name": "Publish recency",
"detail": "latest publish 0 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 0
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "25 published versions",
"points": 20,
"status": "met",
"details": [
{
"code": "published_versions",
"params": {
"count": 25
}
}
],
"max_points": 20
},
{
"key": "not_deprecated",
"name": "Not deprecated",
"detail": "active, not deprecated or yanked",
"points": 20,
"status": "met",
"details": [
{
"code": "package_not_deprecated",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "moderate",
"name": "Engineering Quality",
"value": 62,
"weight": 0.2,
"metrics": [
{
"key": "engineering_practices",
"band": "moderate",
"name": "Engineering practices",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_ci_tests"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 60,
"inputs": {
"has_ci": true,
"has_tests": true,
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": "3 workflow(s)",
"points": 24,
"status": "met",
"details": [
{
"code": "ci_workflows",
"params": {
"count": 3
}
}
],
"max_points": 24
},
{
"key": "tests_present",
"name": "Tests present",
"detail": null,
"points": 24,
"status": "met",
"details": [],
"max_points": 24
},
{
"key": "linter_config",
"name": "Linter config",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 16
},
{
"key": "pre_commit_hooks",
"name": "Pre-commit hooks",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 9.6
},
{
"key": "editorconfig",
"name": ".editorconfig",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.4
},
{
"key": "openssf_scorecard_ci_tests",
"name": "OpenSSF Scorecard: CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "moderate",
"name": "Documentation",
"note": null,
"notes": [],
"value": 65,
"inputs": {
"topics": [],
"has_wiki": false,
"homepage": null,
"has_readme": true,
"has_docs_dir": true,
"has_description": true
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 30,
"status": "met",
"details": [],
"max_points": 30
},
{
"key": "documentation_directory",
"name": "Documentation directory",
"detail": null,
"points": 25,
"status": "met",
"details": [],
"max_points": 25
},
{
"key": "documentation_homepage_site",
"name": "Documentation / homepage site",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "repository_description",
"name": "Repository description",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "topics",
"name": "Topics",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
},
{
"key": "wiki",
"name": "Wiki",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
}
],
"description": "Are baseline engineering and documentation practices in place?"
},
{
"key": "security",
"band": "at_risk",
"name": "Security",
"value": 39,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "at_risk",
"name": "Security posture",
"note": "Excluded from scoring (no data or not applicable): CI-Tests, Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"ci_tests",
"signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 39,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 16,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 2,
"scorecard_aggregate": 3.9
},
"components": [
{
"key": "binary_artifacts",
"name": "Binary-Artifacts",
"detail": "no binaries found in the repo",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "branch_protection",
"name": "Branch-Protection",
"detail": "branch protection not enabled on development/release branches",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 2.5
},
{
"key": "cii_best_practices",
"name": "CII-Best-Practices",
"detail": "no effort to earn an OpenSSF best practices badge detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "code_review",
"name": "Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "contributors",
"name": "Contributors",
"detail": "project has 0 contributing companies or organizations -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "dangerous_workflow",
"name": "Dangerous-Workflow",
"detail": "no dangerous workflow patterns detected",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "dependency_update_tool",
"name": "Dependency-Update-Tool",
"detail": "no update tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "fuzzing",
"name": "Fuzzing",
"detail": "project is not fuzzed",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "license",
"name": "License",
"detail": "license file detected",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "maintained",
"name": "Maintained",
"detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "packaging",
"name": "Packaging",
"detail": "packaging workflow detected",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "all dependencies are pinned",
"points": 5,
"status": "met",
"details": [],
"max_points": 5
},
{
"key": "sast",
"name": "SAST",
"detail": "no SAST tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "security_policy",
"name": "Security-Policy",
"detail": "security policy file not detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 7.5
},
{
"key": "token_permissions",
"name": "Token-Permissions",
"detail": "detected GitHub workflow tokens with excessive permissions",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "vulnerabilities",
"name": "Vulnerabilities",
"detail": "51 existing vulnerabilities detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
}
]
},
{
"key": "high_risk_jurisdiction_exposure",
"band": "excellent",
"name": "High-Risk Jurisdiction Exposure",
"note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
"notes": [
{
"code": "jurisdiction_evidence_limits",
"params": {}
}
],
"value": 100,
"inputs": {
"meaning": "self-published location evidence; not nationality or citizenship",
"red_flag": false,
"exposures": [],
"policy_countries": [
"Russia",
"Iran",
"North Korea"
],
"review_only_matches": 0,
"assessed_self_published_locations": 2
},
"components": [
{
"key": "policy_exposure_multiplier",
"name": "Policy exposure multiplier",
"detail": "no confirmed policy-scope location match",
"points": 100,
"status": "met",
"details": [
{
"code": "jurisdiction_no_match",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
},
{
"key": "ai_readiness",
"band": "good",
"name": "AI Readiness",
"value": 74,
"weight": 0,
"metrics": [
{
"key": "ai_agent_context",
"band": "excellent",
"name": "Agent context & guidance",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"has_llms_txt": true,
"legible_history_share": 0.901,
"agent_instruction_files": [
"CLAUDE.md"
],
"agent_instruction_max_bytes": 6635
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": "CLAUDE.md",
"points": 45,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "CLAUDE.md"
}
}
],
"max_points": 45
},
{
"key": "machine_readable_docs_llms_txt",
"name": "Machine-readable docs (llms.txt)",
"detail": "llms.txt present",
"points": 15,
"status": "met",
"details": [
{
"code": "llms_txt_present",
"params": {}
}
],
"max_points": 15
},
{
"key": "legible_commit_history",
"name": "Legible commit history",
"detail": "64 of 71 human commits state their intent (structured subject or explanatory body)",
"points": 40,
"status": "met",
"details": [
{
"code": "legible_history",
"params": {
"legible": 64,
"sampled": 71
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "moderate",
"name": "Verify loop (build / test / typecheck)",
"note": null,
"notes": [],
"value": 53,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [
"uv.lock"
],
"has_dockerfile": false,
"typed_language": false,
"bootstrap_files": [],
"has_devcontainer": false,
"has_linter_config": false,
"typecheck_configs": [
"wafer/py.typed"
],
"agent_commit_share": 0,
"toolchain_manifests": [],
"dependency_bot_commit_share": 0
},
"components": [
{
"key": "one_command_bootstrap",
"name": "One-command bootstrap",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 18
},
{
"key": "automated_tests",
"name": "Automated tests",
"detail": null,
"points": 22,
"status": "met",
"details": [],
"max_points": 22
},
{
"key": "lint_format_config",
"name": "Lint / format config",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 11
},
{
"key": "static_type_checking",
"name": "Static type checking",
"detail": "wafer/py.typed",
"points": 11,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "wafer/py.typed"
}
}
],
"max_points": 11
},
{
"key": "reproducible_environment",
"name": "Reproducible environment",
"detail": "lockfile",
"points": 10,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "lockfile"
}
}
],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "no agent-authored commits among the last 71",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_agent_authored_commits",
"params": {
"sampled": 71
}
}
],
"max_points": 10
},
{
"key": "automated_maintenance",
"name": "Automated maintenance",
"detail": "no automated dependency updates observed",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_dependency_automation",
"params": {}
}
],
"max_points": 8
},
{
"key": "openssf_scorecard_pinned_dependencies",
"name": "OpenSSF Scorecard: Pinned-Dependencies",
"detail": "all dependencies are pinned",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "good",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 78,
"inputs": {
"primary_language": "Python",
"largest_source_bytes": 395436,
"source_files_sampled": 97,
"oversized_source_files": 8
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "Python with type-check config (wafer/py.typed)",
"points": 27,
"status": "partial",
"details": [
{
"code": "typecheck_config_language",
"params": {
"files": "wafer/py.typed",
"language": "Python"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "8/97 source files over 60KB",
"points": 50.5,
"status": "partial",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 97,
"oversized": 8
}
}
],
"max_points": 55
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
}
],
"metrics_version": "1.13.0"
},
"warnings": [
"Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
"GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
"deps.dev does not index pypi:wafer-py@0.4.3; advisories assessed against the repository dependency graph instead"
],
"report_type": "repository",
"generated_at": "2026-07-29T22:48:32.090849Z",
"schema_version": "0.27.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/a/Averyy/wafer.svg",
"full_name": "Averyy/wafer",
"license_state": "standard",
"license_spdx": "Apache-2.0"
}