sbot Archival Quality Improvements (2026-05)
This document captures concrete problems found during the 2026 grok_test collection and minimal, suckless-style fixes.
The 4 Problems Identified
1. Old Web Mirrors Are Painful (Dead HTTPS + Slow Hosts)
Evidence from tests:
- oocities-org: Flood of "SSL peer certificate or SSH remote key was not OK" on almost every subpage.
- textfiles-com: Repeated timeouts on robots.txt and root, exhausted 3 retries and gave up.
Root causes in current code:
- fetch.c: strict
CURLOPT_SSL_VERIFYPEER=1andVERIFYHOST=2with no option to relax for archival use. - fetch.h: Hardcoded
FETCH_MAX_RETRIES=3and short exponential backoff (base 2s). - No concept of "known slow host" or per-host backoff.
- No way to treat certain certificate errors as non-fatal for old archives.
Proposed minimal changes:
- Add
IGNORE_SSL_ERRORScompile-time option in config.h (default 0 for safety). - Increase default retries or make
FETCH_MAX_RETRIESand backoff tunable in config.h. - Consider a small "known bad hosts" mechanism or at least better logging.
2. Pathological Bloat Risk
Evidence:
- lowendmac-com ballooned to 250MB with only 5 files because early pages inlined enormous images.
Root causes:
MAX_FILE_SIZE(50MB) is defined in config.h but never enforced during fetch or inlining.- No per-resource size cap is passed to libcurl (
CURLOPT_MAXFILESIZEis not used). - No early rejection of giant resources before base64 inlining (which multiplies memory).
Proposed minimal changes:
- Actually wire
MAX_FILE_SIZEinto fetch.c (use CURLOPT_MAXFILESIZE + check after download). - Skip inlining resources over a certain size (new config option or reuse MAX_FILE_SIZE).
- Add a warning when a resource is skipped due to size.
3. Timeout Fragility on Slow Sites
Evidence:
- Multiple runs (including stretch targets) were killed by the 3-minute external tool timeout before sbot could finish.
- textfiles and oocities both showed repeated "Timeout was reached".
Root causes:
- REQUEST_TIMEOUT is 60s (reasonable).
- But there is no progressive backoff for hosts that are consistently slow.
- No "slow host" tracking that increases timeouts or reduces parallelism for that host.
- The global rate limit (RATE_LIMIT_MS) is the only politeness mechanism.
Proposed minimal changes:
- Make REQUEST_TIMEOUT and CONNECT_TIMEOUT configurable in config.h (they already are, but document better).
- Add optional "slow host" backoff (simple host hash + failure counter).
- Consider a compile-time
ARCHIVAL_MODEthat is more patient.
4. Asset Writing Failures on Messy Filenames / Long Paths
Evidence:
- vintage-computer-com had many "cannot write asset" warnings for paths like
2020test/images/chmopenhouse/...with long or special names.
Root causes:
url_to_path()does basic query/hash stripping and extension logic, but does almost no sanitization of the actual path components.- No truncation of overly long filenames.
- No replacement of characters that are problematic on some filesystems.
sanitize_filename()exists but is only used for the top-level output directory name.
Proposed minimal changes:
- Improve
url_to_path()(or add a helper) to sanitize individual path segments:- Remove or replace dangerous characters (
/ \ : * ? " < > |). - Truncate overly long segments.
- Optionally percent-decode for nicer on-disk names (optional, behind define).
- Remove or replace dangerous characters (
- Make the sanitization behavior controllable via config.h for "strict archival" vs "nice filenames".
Design Principles for Fixes
- All changes must be compile-time (config.h) where possible — suckless style.
- No new dependencies.
- Keep the binary small and the code auditable.
- Prefer failing safely / warning over crashing or producing garbage archives.
- Improve robustness for the "primary archival" use case the user wants, without weakening safety for normal use.
Implementation Order (Minimal Impact First)
- Wire up
MAX_FILE_SIZEenforcement (biggest bloat win). - Add
IGNORE_SSL_ERRORSoption (biggest old-web quality of life win). - Improve filename sanitization in url_to_path.
- Make retry / timeout values more configurable + add simple slow-host backoff.
- Update documentation and defaults if needed.
Implemented Changes (2026-05)
All changes follow suckless principles: compile-time configuration, minimal diff, no new dependencies.
1. MAX_FILE_SIZE Enforcement (anti-bloat)
- Wired
CURLOPT_MAXFILESIZEinto libcurl. - Added post-download size check in fetch_url.
- Added guard in fetch_and_encode before base64 inlining.
- This directly addresses the lowendmac 250MB bloat case.
2. IGNORE_SSL_ERRORS Option (old web support)
- New define in config.h (default 0 = strict).
- When set to 1, relaxes SSL peer/host verification.
- This makes archiving old Geocities-style mirrors and dead personal sites practical without constant warnings or early failure.
3. Improved Filename Sanitization
- Added character sanitization in url_to_path (replaces \ : * ? " < > | with _).
- Helps with the long/weird paths seen in vintage-computer dumps.
4. Better Defaults for Archival Use
- Increased
FETCH_MAX_RETRIESfrom 3 → 5. - Increased default
REQUEST_TIMEOUTfrom 60s → 90s. - These give more resilience on slow historical hosts without changing behavior drastically for normal use.
These changes make sbot significantly more robust as a primary archival tool while keeping the codebase small and the philosophy intact.