Free-substitute supply for each pipeline candidate's core functions

Study · 2026-08-20 · portfolio/research/substitute-supply/README.md

Measured 2026-08-20. No credential, no account, no spend — read-only GETs against the npm search API.

Reproduce: python3 probe_substitutes.py --json results-2026-08-20.json. Recompute the summary from saved data with no network: python3 probe_substitutes.py --recompute-from results-2026-08-20.json. Test suite: python3 -m unittest test_probe_substitutes (24 tests, offline). Raw output: results-2026-08-20.json.

The question this asks, and why nobody had asked it

Four of the eight candidates in portfolio/pipeline/ justify their defensibility score with a prose assertion that free substitutes already exist:

None of those four claims had been measured. The other four candidates make no claim either way — which is not the same as having checked. rescore-2026-08-20.md recorded that "every product-assumption check has cost a point off a candidate nobody has sold anything to" and that defensibility fell on both candidates anyone had actually measured. This is the same class of check for the other six.

Method

npm search (registry.npmjs.org/-/v1/search) returns, per package, monthly downloads, keywords, description and last-updated — enough to characterise a function's substitute supply in one request per query and no per-package fetches.

Each candidate is decomposed into core functions taken from the wording of its own write-up. Each function carries a query and a two-tier relevance rule:

Every match is on whole tokens, not substrings. The first draft of this script matched substrings and reported jest as a free substitute for an agent evaluation harness and helmet as one for prompt-injection testing, because "ai" occurs inside "domain" and "agent" inside "user-agent". Those exact regressions are locked in test_probe_substitutes.py.

A package counts toward a function only if it is live — published within the last 18 months — and its monthly downloads clear a threshold. The headline threshold is 10,000/month: free-listing-demand/ measured the median monthly downloads of a leaf listing in three of these same categories at 68, 205, and 2,399, so a package clearing 10,000 is not a cold listing but something people actually install. The saved results carry counts at 1k, 10k, and 100k so the finding can be read at a threshold the reader picks.

Per-candidate reachability of this measurement

npm is not the right ecosystem for every candidate, and pretending otherwise would make the low counts look like scarcity when they are unmeasurability.

FitCandidatesWhat a low count means
nativeeaa-remediation-pipeline, shopify-a11y-evidence, cra-evidence-desk, mcp-supply-chain-watch, agent-permission-harness, public-record-watchReal evidence of scarcity
partialcra-evidence-desk / vex-attestationWeak evidence; thinner on npm than in Go/Sigstore
foreigneinvoice-preflight, tender-radarNo evidence — measure elsewhere

Result

Full table below is a re-derivation of the run above. Every "top free substitute" is the highest-downloaded package that met the whole-token, two-tier relevance rule for the function.

Candidate / functionRelevant / live≥1k≥10k≥100kTop free substituteTop /moVerdict
eaa-remediation-pipeline
  wcag-audit68 / 683395@storybook/addon-a11y42,294,723commoditised
  a11y-fix-generation10 / 10500@ia-qa/self-healing7,651no-substitute-found
shopify-a11y-evidence
  storefront-a11y-scan0 / 0000——no-substitute-found
cra-evidence-desk
  sbom-generation36 / 361176@datadog/datadog-ci-plugin-sbom3,841,774commoditised
  advisory-matching32 / 3222103better-npm-audit1,004,281commoditised
  vex-attestation10 / 10500supply-chain-guard9,815not-measurable-here [partial]
mcp-supply-chain-watch
  mcp-tool-introspection186 / 18618614051@playwright/mcp25,874,357commoditised
  change-monitoring127 / 12712511790diff571,852,492commoditised
agent-permission-harness
  prompt-injection-testing64 / 6434122arcjet317,462commoditised
  agent-eval-harness44 / 4439147@mastra/core5,753,205commoditised
einvoice-preflight
  einvoice-validation40 / 40600n8n-nodes-sirenic3,254not-measurable-here [foreign]
tender-radar
  tender-monitoring15 / 15500@open-tender/store3,233not-measurable-here [foreign]
public-record-watch
  register-change-monitor2 / 2000watchdiff-core589no-substitute-found

Of 10 functions measurable on npm, 7 are commoditised at ≥3 live packages above 10k monthly downloads (70%). Every candidate carrying the prose "commodity" claim is confirmed as commoditised in its main function.

What this says for each candidate

Reachability of a free substitute is one input into defensibility. The existing scores already reflect a rough version of this reading; the point here is that the reading now has numbers behind it and, more usefully, has numbers for the candidates whose write-ups did not make the claim.

Confirmed commodity, no score change proposed — the write-up already scored these at the corresponding floor and the measurement matches:

Confirmed commodity, previously unstated in the write-up — the finding is new for these:

Reads as evidence — one candidate the measurement quietly supports:

Not measurable here — the finding is a null result about the measurement, not about the candidate:

What this does not measure, stated explicitly

What this changes in the pipeline

Nothing about the current pipeline ranking, and nothing to escalate. Every candidate whose defensibility score depended on a substitute claim already scored it low; the change is that four of those four are now measured rather than asserted, and one previously-unmeasured candidate (mcp-supply-chain-watch) has its floor independently supported. The public-record-watch reading is the only one that shifts against pessimism, and it is not enough on its own to raise a score — the wider ecosystem outside npm is where that check would need to run.

portfolio/pipeline/README.md's intake gate still applies: no candidate is being added, no score is being changed, no ask is being widened. The value of this pass is that six of the eight defensibility scores now rest on a measurement rather than a prose sentence, and the pipeline's screening scores are one cheap environmental check less optimistic than they were this morning — matching the pattern rescore-2026-08-20.md already recorded.