%%{init: {"theme":"base","themeVariables":{"fontFamily":"ui-sans-serif, system-ui","fontSize":"14px","primaryColor":"white","primaryTextColor":"rgb(39,128,227)","primaryBorderColor":"rgb(17,17,17)","lineColor":"rgb(52,58,64)"},"flowchart":{"curve":"basis","nodeSpacing":50,"rankSpacing":70,"edgeLabelBackground":"white","htmlLabels":true}}}%%
flowchart TB
A2[stdin] --> A3["1 ingest: grammar parse + dedupe"]
A3 --> B0["2 enrich: shard filter + DNS pool (A/AAAA/PTR)"]
B0 --> C0["3 scheduler: fair target queue + plan builder"]
C0 --> D0["4 TCP engine - crypto/tls + uTLS"]
C0 --> D2["4 QUIC engine - quic-go"]
D0 --> E0["5 classify + score + WAL + encoders"]
D2 --> E0
E0 --> OUT[jsonl / csv / text / urls - streamed]
C0 -.- FC[AIMD + circuit breakers]
Design and architecture
Where the time goes
A fast-mode handshake is RTT-bound. The network time, not the processor time, sets the pace.
L ≈ one connect RTT + one handshake RTT — one more RTT when an HRR hop forces a second flight
+ server_compute (~50–300 ms, CDN edge)
+ client_crypto (MLKEM-768 encap ~0.05–0.15 ms; negligible)
The throughput for a pool of W concurrent connections is T ≈ W / L. The budget table below, not the thread count, sets the rate.
The pipeline: five bounded, streaming stages
Design rules: no stage waits on a slow item. Bounded channels carry the backpressure. Worker pools carry the explicit budgets. Everything streams. Only -sorted buffers. Ctrl-C drains the run. The WAL stays consistent.
Budgets
| Budget | Default | Rationale |
|---|---|---|
| Global in-flight connections | 50,000 | T ≈ W/L; ~2 GB RAM with 20–40 KB/conn |
| TCP in-flight | 40k | QUIC conns are ~5× heavier |
| QUIC in-flight | 10k | per-conn goroutines + timer wheel |
| Deep-mode probes per target | 6–8 concurrent | rate-limit avoidance: servers reject bursts |
| Per-subnet (/24) concurrent | 64 | NAT/policy devices fail closed |
| Global rate cap | 20k handshakes/s | etiquette default |
| DNS in-flight | 256 | PTR storms must not starve handshakes |
| Deadline ladder | connect 2 s / handshake 4 s / probe 8 s (±20 % jitter) | bounds the tail; de-synchronises retries |
| Retries | 1, transient-only | rejections are results, not errors |
Adaptive control
The global concurrency ramps toward its cap. An error-rate spike halves the window. A circuit breaker cools a bucket that times out repeatedly. A cooled target emits a skipped record with the reason. The run shows no silent gaps. A probe plan runs 6–8 probes per target. Each probe carries its own deadline. The scheduler is weighted-fair. One bad subnet cannot block the run.
Probe-plan model (deep mode)
%%{init: {"theme":"base","themeVariables":{"fontFamily":"ui-sans-serif, system-ui","fontSize":"14px","primaryColor":"white","primaryTextColor":"rgb(39,128,227)","primaryBorderColor":"rgb(17,17,17)","lineColor":"rgb(52,58,64)"},"flowchart":{"curve":"basis","nodeSpacing":50,"rankSpacing":70,"edgeLabelBackground":"white","htmlLabels":true}}}%%
flowchart TB
P[profile handshake<br/>version, suite, group, ALPN, cert] --> S[suite matrix<br/>1.0-1.2: offer-one/observe<br/>1.3: fixed set accepted?]
R2[pq forced-group ladder<br/>4585–4590 + drafts] --> S
S --> T[sigalg matrix incl. mldsa, composite]
T --> U[feature probes: HRR, 0-RTT,<br/>resumption xN, SCSV, renegotiation]
U --> V[quic plane if hinted<br/>or -quic-always]
V --> W[classify + score + emit]
The profile handshake prunes the plan. A suite that already negotiated does not re-probe. A group the server re-routed via HRR carries its mark. The default plan caps at 24 probes per target. -deep full unlocks the complete matrix: 80 probes on the current registry snapshot. The list auto-tracks crypto/tls.
PQC classification
Every negotiated or observed parameter gets its class from the generated registry tables: pq | pq_hybrid | classic | draft | unknown. The readiness rating rides the record as pq=<label>(<score>). The bands: pq-ready, pq-ready-hybrid, pq-partial, pq-missing. The record also carries the HNDL flag. HNDL names a classic-only key exchange with long-lived certificates. Recorded traffic then stays decryptable to a future quantum attacker.