# Servo Readiness FAQ ## What is the project's approach and what are the recent changes? ### Approach This project evaluates **Servo's readiness against Baseline "Widely Available" web features** by combining multiple data sources: 1. **WPT pass rates** — Servo's test results mapped to web-feature IDs via the Web Features Manifest 2. **Historical velocity** — Quarterly snapshots (2023-Q3 → 2026-Q2) to track improvement over time 3. **Projections & cost modeling** — Estimating timelines and staffing to reach readiness targets 4. **Real-world usage signals** — 5 parallel signals (HTTP Archive custom metrics, HTTP Archive Blink features, ChromeStatus popularity, Firefox desktop & Fenix use-counters), each kept as an independently-sourced value — **no blended composite** ("say but source it") — so effort can be prioritized by actual web usage The philosophy is **inclusive data, expert-facing**: keep all features, annotate confidence levels and flags (e.g. `single_source`, `generic_observable_only`, `chrome_firefox_divergent`) rather than filtering anything out. ### Recent Changes - **One-pager refinements** — Layout polish, copy fixes ("would" → "could"), updated reference rates, shortened content, breathing room around footer - **Shared metrics & one-pager generator** — Extracted common metrics into a reusable module; added `one-pager.html` / `one-pager-document.html` generation - **Salary/cost model updates** — Unified report styling across outputs - **HTTP Archive usage pipeline** — Full pipeline from BigQuery queries through parallel per-source signals to `web-feature-usage.json` and interactive `web-feature-usage.html` dashboard - **Firefox use-counter telemetry** — An independent signal (desktop + Fenix, ~194/191 features), enabling Chrome-Firefox cross-validation - **Parallel-signal model (no composite)** — every source is kept as an independent, labeled value; no weights, no blend. Derived views (representative value, tier, confidence, cross-engine) are computed on read via `scripts/lib/usage.mjs`. 707 of 919 features have ≥1 signal --- ## How do we map WPT, SpiderMonkey tests, and other things implemented in Servo to BCD keys and Web Features? There are **two independent mapping chains** — one for readiness (WPT pass rates), one for usage (real-world prevalence). Both ultimately key everything to **web-feature IDs** from the Web Features project. ### WPT → Web Features (Readiness) The **Web Features Manifest** (`WEB_FEATURES_MANIFEST-*.json`) is the primary bridge. It maps each web-feature ID to a list of WPT test paths. `analyze.mjs` loads Servo's WPT results (`servo-wpt-summary.json`) and scores each feature by looking up which tests belong to it and computing `passed_subtests / total_subtests`. This is straightforward — the Web Features project maintains this manifest, and we consume it directly. ### BCD Keys → HTTP Archive / Firefox (Usage) For usage data, the chain is longer: 1. **`popularityBcdMap.json`** (from the AreWeBrowserYet collector) maps web-feature IDs → BCD entries + ChromeStatus popularity. This is our starting point for knowing *which BCD keys belong to which web-feature*. 2. **`build-httparchive-mapping.mjs`** translates BCD key patterns into HTTP Archive observable paths via pattern matching (e.g. `css.properties.flex-basis` → `css.properties.flex_basis` in HA custom_metrics, `api.Fetch` → blink_features UseCounter). Not all BCD keys have observables — `javascript.builtins.*` can't be observed in crawl data. 3. **`collect-httparchive.mjs`** queries BigQuery using those mappings. It also classifies observables as **specific** (the property *is* the feature) vs **generic** (a common parent property, e.g. `display` for flexbox) — these are tracked separately: the generic observable is kept as a labeled upper bound in `recovered`, never a scored value. 4. **`collect-firefox.mjs`** takes a parallel path — mapping BCD keys to Mozilla's use-counter telemetry IDs for both desktop and Fenix. 5. **`build-usage-json.mjs`** assembles all sources as parallel per-source values per web-feature — no composite. Derived views come from `scripts/lib/usage.mjs`, the single owner of the on-disk shape. ### SpiderMonkey / JS Built-ins — The Gap **79 JavaScript built-in features** (Promise, async/generators, typed arrays, etc.) have no WPT manifest entries because they're tested via SpiderMonkey's own test suites (test262, jstests), not WPT. They're also not observable via HTTP Archive crawls. These are classified as `noDataByReason: "js-builtin"` — acknowledged but not scored. Similarly, ~20 WebGL extensions and some trivial semantic HTML elements fall into "no-data" categories. ### Design Choices - **Inclusive over conservative**: Features with only generic observables are kept and annotated (`generic_observable_only` flag) rather than dropped. - **Confidence instead of filtering**: Every feature gets a confidence level (high/medium/low/none) based on source count and cross-source agreement, letting experts judge for themselves. - **Cross-validation**: 92 features have both Chrome and Firefox data (cross-engine), enabling divergence detection (`chrome_firefox_divergent` flag when delta > 15%). --- ## How do we estimate current FTEs? ### Current FTEs: 13 Derived from **git commit activity** over a recent 7-month window (2024-Q4 to 2026-Q1): - Counted unique commit authors (bots excluded) — 115 total - Estimated each author's FTE fraction: `commits / 22 per month`, capped at 1.0 - Summed to **~13 FTE**, with 9 core contributors at ≥50% ### Velocity from Those FTEs At 13 FTE, Servo completes **~50 web-features per year** (corrected annualized rate from the last four complete quarters; an earlier ~22/yr figure was a quarter-counting bug). BWA grows at **~52 features/year**, so Servo is **roughly at velocity parity** — it's holding pace, not closing the backlog. ### Scaling Model (Brooks's Law) FTE-to-velocity uses a **sublinear scaling exponent of 0.7** — doubling headcount doesn't double output: ``` completionsPerYear(fte) = 50 × (fte / 13)^0.7 ``` **Velocity parity** (matching BWA's growth rate) requires: ``` parityFTE = 13 × (52 / 50)^(1/0.7) ≈ 14 FTE ``` Because base velocity is already near parity, usage-prioritized scoping (dropping features with <1–5% real-world usage) barely moves this — parity is roughly the current **~13–14 FTE**, not a large hire-up. The open problem is the 338-feature backlog, which needs a rate *above* 52/yr to close, not just match. ### Cost Model - **Base salary**: €150k (European senior SWE median total cost to employer) - **Specialization multiplier**: 1.33× (browser-engine niche + multi-disciplinary: dev + standards + open-source community) - **Effective rate**: €200k/year per FTE - Calibrated against NLnet (€117k), Sovereign Tech Fund (€79–101k), Mozilla Germany (€145–164k), and Servo's own US contractor grant rate (€248k) Parity at ~14 FTE ≈ **€2.8M/year**, with 3-year and 5-year totals computed accordingly. (Closing the backlog by a target year costs far more — see the cost-estimates report's scenarios.) The `opex-addendum.html` adds management overhead ratios (1 EM per 7 engineers, VP at 15+, CTO at 25+) and non-engineering costs.