| The scrape and md commands are two branches of one handler. md reads a file without fetching and takes an optional base; scrape goes to the network only for http or https sources. | Read from the code | webfold/src/main.rs:417-442; webfold/src/main.rs:424-430 | md reads with std::fs::read_to_string and takes the base from argument 3. The URL branch calls acquisition_cli::scrape and returns before the JSON printer. |
| Main-content selection uses 296 features per block, a two-stage model and a default keep threshold of 0.35. | Read from the code | webfold/src/html_extract/main_select/mod.rs:23; :372-398; webfold/src/html_extract/main_select/model.rs:1-3 | NF = NUMERIC + 2*BINS + LEX_BINS = 40 + 128 + 128. DEFAULT_THRESHOLD = 0.35 (line 383). select_main returns the whole page when no block reaches the threshold (lines 387-398). model.rs is generated by tools/main_select/gen_model.py. |
| Selection runs only for the file branch of md and scrape and for the search route. The URL scrape path and the library scrape call to_blocks and render directly. | Read from the code | webfold/src/main.rs:462-469; webfold/src/cli/route.rs:27-31; webfold/src/lib.rs:404-406; webfold/src/lib.rs:474-476 | A search for select_main call sites finds only main.rs and cli/route.rs. lib.rs scrape and scrape_tiered_inner call to_blocks and render(&blocks, None, 1) with no selector. |
| Elements are contained by a fixed drop list, and figure and header inside main or article are transparent. | Read from the code | webfold/src/html_extract.rs:86-146; webfold/src/html_extract/content.rs:157-200 | DropTag::from_tag maps script, style, noscript, svg, head, nav, header, footer, aside, form, button, iframe, template, dialog, select, option and figure. content.rs marks figure and header-in-main as transparent and treats aside as soft unless it sits inside main. |
| Hidden content is detected by attributes, a fixed id and class list, and inline display or visibility. | Read from the code | webfold/src/html_extract/content.rs:234-340; webfold/src/html_extract/content.rs:342 | Rules: the hidden attribute, type=hidden, ids such as wayback-toolbar and __VIEWSTATE, class tokens for ad and cookie-consent chrome (including the cookieconsent- prefix), and hidden_style for inline display and visibility. |
| Embedded payloads are read only on thin pages, using a named list of hydration kinds. | Read from the code | webfold/src/html_extract.rs:945-947; webfold/src/html_extract.rs:257-269; webfold/src/html_extract.rs:865-902 | Unpacking runs when there are no blocks or fewer than 50 words. Kinds: NextData, NextAppRouterRsc, Nuxt3Data, SvelteKit, RemixContext, AngularState, JsonLd, PageContentHtml and StructuredHtml (the last two need the native feature, which is in the default build). tests/parser_review.rs:89 hidden_scripts_do_not_supply_hydration_content checks the hidden-script rule. |
| Entity decoding handles 13 named entities and numeric references. Other named entities are not decoded. | Read from the code | webfold/src/html_extract.rs:1045-1100 | Named: amp, lt, gt, quot, apos, nbsp, mdash, ndash, hellip, rsquo, lsquo, ldquo, rdquo. An unrecognised name leaves the ampersand in the output as a literal character. |
| Links and images keep scheme and protocol-relative targets unchanged. | Read from the code | webfold/src/html_extract/url.rs:1-6; webfold/src/html_extract/url.rs:196-205; webfold/src/html_extract.rs:1382-1400 | resolve_url returns any href that has a scheme, starts with // or starts with #, unchanged. The module doc says this is not WHATWG canonicalisation, network validation or an SSRF policy. The test resolve_preserves_dangerous_and_non_http_schemes asserts javascript:, data: and blob: pass through. Read, not run. |
| Tables become pipe tables only when the grid fits a size budget; otherwise rows are written unpadded. Spans are not expanded. | Read from the code | webfold/src/html_extract/table.rs:93-140; ARCHITECTURE.md:8-20 | markdown() checks grid_slots against 2 * source_cells + width. ARCHITECTURE.md describes the same rule and says spans are not expanded. |
| Table, nested table and span behaviour has named tests. | Covered by a test | webfold/tests/corpus_review.rs:10, 64, 168, 200 | Tests column_headers_and_rows_form_one_contiguous_table_block, excessive_rectangular_padding_keeps_unpadded_rows_and_links, nested_tables_keep_content_without_claiming_nested_grid_fidelity and spans_retain_source_cells_without_inventing_expanded_values. Read, not run. |
| Fenced code, language classes, images, entity decoding and script stripping have named tests. | Covered by a test | webfold/tests/firecrawl_compat.rs:144, 232, 352, 433, 474 | test_fenced_code_blocks, test_images, test_pre_code_language_classes, test_html_entity_decoding and test_script_tags_completely_stripped. The file header says these were ported from a Firecrawl suite whose source is not in this checkout. Read, not run. |
| Hot and fresh-process conversion times against the Rust html-extractor on 54 fixtures. | Measured | benchmark slug html-conversion; webfold/README.md:70 | README records 4.601 µs (Webfold) against 17.829 µs for the Rust html-extractor, hot, and 0.371781 ms against 4.021488 ms, fresh process, with 52 of 52 asserted fixtures passing on both. It is a historical five-run measurement on one host. The manifest it cites (benchmarks/review/h2h/manifest.json) is not in this checkout, so the figures are cited, not re-derived. |
| Main-content F1 on the WCXB held-out test split is 0.861, with precision 0.834 and recall 0.931. Before selection it was 0.815. | Measured | benchmark slug extraction-quality; webfold/docs/WCXB-MAIN-SELECT.md (results table) | Test split: F1 0.861, precision 0.834, recall 0.931. md before the selector: 0.815, 0.743, 0.968. Development 5-fold cross-validation: 0.812. The doc says the selector was trained on the development split only and the test split was scored once. The WCXB dataset is not in this checkout, so the figures are cited from the doc and the benchmark record. |
| A charset helper in the headless engine, with unit tests, decodes a fetched page in its declared charset. The to_blocks function does not use it. | Read from the code | webfold/src/headless.rs:1307-1322; webfold/src/headless.rs:2600-2625 | document_encoding checks a byte order mark, then the Content-Type charset, then a meta prescan of the first 1024 bytes, then falls back to UTF-8. The tests in document_encoding_tests cover these cases. decode_document is called when a URL is scraped (webfold/src/lib.rs, tiered scrape), so a Shift_JIS or GBK page is decoded instead of turning into replacement characters. File input and to_blocks still take a &str. |