Skip to content

Add adaptive extraction, typed anti-bot mitigation, and identity profiles - #1

Open
satvik007 wants to merge 19 commits into
mainfrom
fix/review-retry-identity
Open

Add adaptive extraction, typed anti-bot mitigation, and identity profiles#1
satvik007 wants to merge 19 commits into
mainfrom
fix/review-retry-identity

Conversation

@satvik007

Copy link
Copy Markdown
Owner

Summary

  • bring the previously local adaptive streaming extraction and performance work into a reviewable branch
  • add typed anti-bot detection and mitigation across HTTP, HTML, smart, and browser crawlers
  • add deterministic cross-layer identity profiles, proxy/session feedback, and Chromium overrides
  • preserve authoritative block actions and retry identity/proxy state across promotion failures, observation-free errors, and panics
  • map client-hint platform brands to consistent navigator.platform values
  • update public docs, API baselines, roadmap, templates, and tests

Review fixes

  • status promotion applies only to errors without typed BlockFailure metadata
  • failed legacy browser promotion propagates the original session-rotation error
  • applied session and proxy overrides survive panicked attempt tasks
  • observation-free retries fall back to the applied session
  • Chromium maps Windows/macOS/Android/Linux client hints to navigator platform values

Verification

  • cargo fmt --all -- --check
  • git diff --check
  • cargo test --workspace
  • targeted core engine, smart browser, and Chromium provider regression suites

cargo test --workspace --all-targets also passed all library, integration, real-browser, and benchmark targets until the existing millipede-http client_overhead benchmark oversized-header case exceeded the HTTP message-head limit.

satvik007 and others added 19 commits July 24, 2026 13:09
… control, engine filter, compare helper (Track D / S4)

- conformance scenario (new): adversarial-HTML HtmlProcessingMode parity
  gate. Corpus covers adoption-agency misnesting, foster parenting,
  template/noscript, RAWTEXT/RCDATA/plaintext apparent anchors,
  multiple/invalid <base>, entity-encoded hrefs (incl. legacy
  no-semicolon and an entity-encoded colon), fragments, traversals,
  SVG/MathML/foreignObject, an XHTML-content-type page, and a non-UTF-8
  page. Ground truth is a simulated DOM-path crawl (same scraper version,
  mirrored resolve/strategy/unique-key semantics); trials must reproduce
  the discovered-URL/request-ID digest (server-relative, port-independent)
  plus the server hit-set/off-host gates. 12 unit tests pin per-construct
  DOM behavior; end-to-end smoke validates against a real millipede crawl.
- millipede-adaptive engine variant: explicit Adaptive row for the gate;
  bails with a clear error until Track A lands (TODO(track-a) markers
  carry the exact one-line opt-ins for the engine and the headline row).
- phase timing (opt-in via SPIDER_BENCH_PHASES): handler/accounting/
  extract/enqueue wall-time sums per millipede trial, emitted into
  samples.jsonl and a residual-CPU decomposition section in summary.md;
  absent otherwise.
- compressed-identity scenario: compressed corpus served identity-encoded
  (identical bodies/checksums/gates) to isolate gzip CPU (B2 control).
- orchestrate --engines filter (composes with --scenario/--quick; skips
  Go/npm preparation when external engines are filtered out).
- compare subcommand: before/after per-(scenario, C, engine) medians with
  deltas over two samples.jsonl files.
- server: *.xhtml paths served as application/xhtml+xml (pre-rendered
  bodies cannot carry per-page metadata).
- docs: disclosure + diagnostics section in benchmarks-vs-crawlers.md;
  README run/diagnostics updates; rustfmt normalization of the package.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add HtmlProcessingMode { EagerDom (default), Adaptive } to HtmlKind.
EagerDom is bit-identical to previous releases, including eager parse
timing in execute(). Adaptive defers the scraper DOM behind
SynchronizedHtml's new lazy representation (bytes::Bytes source +
OnceLock<Mutex<scraper::Html>>; public API unchanged, parse-exactly-once
under concurrent first touch) and dispatches default-selector link
discovery per extract() call:

- EagerDom, custom selectors, XHTML content types, non-UTF-8 bodies,
  and already-materialized DOMs take the DOM path (previous code,
  verbatim; DOM-reuse keeps books/hn-style DOM-first handlers on
  ADR-0005's d2 path with zero streaming passes);
- everything else runs a synchronous lol_html pass (new stream.rs)
  that never crosses an .await and never fails a request — any
  rewriter error falls back to the DOM path.

Parity contract (hard gate): streaming produces the DOM path's resolved
URL set, unique keys, and RequestIds, or statically routes to DOM.
Enforced by htmlize::unescape_attribute entity decoding (attribute-mode
legacy rules, only when the raw value contains '&') plus U+0000 -> U+FFFD
tokenizer parity; first-base[href]/invalid-base semantics mirroring
extract.rs; RequiresDom aborts on <select>/<frameset> subtrees (html5ever
drops their illegal children); pinned-construct fixtures (template,
noscript/raw-text containers, SVG/MathML/foreignObject/CDATA, adoption
agency, foster parenting, duplicate attributes); two differential
proptests (256 cases each); and frontier-determinism tests across four
handler shapes in both modes. Adaptive parse time is attributed to
request_handler_timeout — documented and tested.

Deps: lol_html =2.8.1 moves dev->prod in millipede-html; htmlize 1.1
(MIT OR Apache-2.0, unescape feature) and bytes added; cargo deny and
cargo +1.85 check clean. Public-API baselines regenerated for millipede
and millipede-html (additive only; bench-only internals are doc(hidden)
and excluded).

Benches (link_extraction, new adaptive_extraction groups at
4/32/256 KiB): streaming_cold beats dom_cold 3.7-4.2x; dom-first
dispatch within noise of dom_warm; selector_bench d2 within +/-2.4% of
the ADR-0005 baseline. Full gate results recorded in ADR-0009.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…/ S2)

Check the enqueue strategy before serializing candidate URLs, thread a
single owned URL string through the filtered-candidates/seen/request_urls
checks, and skip the post-transform unique-key recompute when no transform
is configured. Adds a fixture-matrix test that diffs the optimized pipeline
against a test-only pre-optimization reference across strategies, filters,
limits, transforms, and duplicate paths, plus a criterion benchmark
(enqueue_pipeline) to measure the allocation-diet win.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Gate success-path snapshot cloning on subscriber presence (failure path
and failed_handler untouched); move Arc<Request> through the pipeline
instead of cloning, recovering ownership via Arc::unwrap_or_clone; slim
LeasedIdentity while preserving mark_handled's stored-identity semantics;
merge dedup/handled tracking into a single HashMap<String, DedupEntry> in
millipede-storage-memory; keep reclaim/abandon/renew re-queueing
lease.request unchanged; cache the no-proxy HTTP client to skip the
per-hop mutex and mem::take response headers on both buffered and
streaming paths. Adds engine_overhead/queue_ops bench coverage and a new
client_overhead bench (no-proxy, redirect chain, buffered vs streaming,
large headers).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Post-merge integration: activate Track A's HtmlProcessingMode::Adaptive in
the spider-bench millipede-adaptive engine, run the conformance scenario as
an EagerDom/Adaptive pair, and pin spider-bench's lockfile to lol_html 2.8.1
to match millipede-html's new production pin.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review findings D-1..D-4: fold stored RequestIds and per-page strategy-skip
counts into the conformance frontier digest so ID-derivation or off-host
divergence between EagerDom and Adaptive fails the trial; refuse --engines
filters that silently degrade the conformance pair to single mode (explicit
single-engine runs stay possible, loudly disclaimed); rework the phase
table as an honest cumulative handler wall-time decomposition instead of
an unsound residual-CPU subtraction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ing divergence

Review finding A-1 (critical) investigated empirically and refuted:
scraper::Html::select iterates the ego_tree arena in node-creation order
(token order), not document order, so html5ever's table foster parenting
never reorders extraction relative to the streaming pass. Instead of a
routing change, harden the contract: differential tests and proptests now
compare ordered deduplicated frontier sequences (mirroring enqueue's
dedupe-before-limit), with regression fixtures for fostered base/anchor,
.limit() truncation prefixes, adoption-agency clones, and an adversarial
table battery — these fail loudly if a scraper upgrade ever switches to
document-order traversal. ADR-0009 restates the ordered contract and the
formatting-clone tolerance. Also gate the handler-timeout overrun test to
debug profile where its 200 ms parse-budget assumption holds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The dual-mode conformance gate passed 5/5 trials with identical frontier
digests, satisfying the plan's flip criterion. Headline Engine::Millipede
rows now opt into HtmlProcessingMode::Adaptive (library default remains
EagerDom); conformance trials keep this arm on EagerDom so the gate always
compares the two modes. Disclosure updated in docs/benchmarks-vs-crawlers.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant