ADR-0010 Amendment 1 — UN-S1 fallback chain and universal-rule source discipline
Status: Accepted Date: 2026-05-20 Amends: ADR-0010 (Universal rule layer — UN-prefixed rules) Context: Cycle 11 (pre-cycle-2 scoping fixes)
What changed
ADR-0010's "consequences to verify" section listed "UN-S1 source mix for non-UK institutions" as the awkward case. Cycle 10.5 (INST-0009 / HSBC Hong Kong signal read, run 8) confirmed it bites. This amendment records the finding, the chosen fix, and the broader design principle it surfaces.
Empirical finding (cycle 10.5 / cycle 11)
UN-S1.3 (Human rights due diligence — universal rule, applicable_sectors='ALL') has source_id = 'UK-MSA-REGISTRY' in the rule table. The UK-MSA scraper contains a country guard: if (inst.country_hq !== 'GB') return []. For INST-0009 (HSBC Hong Kong, country_hq='HK'), the scraper returned [] silently — no signal row, no skip record, no diagnostic. The source register showed UK-MSA-REGISTRY as healthy because the scraper succeeded; the per-institution gap was invisible.
This means any non-GB institution (financial or not) has always had a silent no-data state on UN-S1.3, with no way to distinguish it from "rule not evaluated" or "scraper failed."
Chosen fix (option ii from the audit)
The country guard now:
-
Writes an explicit skip record to the new
scrape_skiptable (migration 016) withreason = 'country_hq=<code> (requires GB)'. This makes the skip visible in diagnostics. -
Returns an honest no-data signal for
UN-S1.3withboolean_value=false, extraction_ok=true, confidence=0.0. The signal is distinguishable from a missing-row scenario: it says "the scraper ran, found that the source doesn't apply to this institution, and is explicitly recording no data."
S1.3 (financials-only, UK-only, applicable_sectors='40') is not affected — the country guard on that rule path is semantically correct. A non-UK financial institution genuinely has no UK Modern Slavery Act obligation, so no signal and a skip record is the right state.
The fallback chain intent: UN-S1.3 reads UK-MSA-REGISTRY for GB institutions; for non-GB institutions, it defers to CORP-WEBSITE (pending, ships in v2). Until CORP-WEBSITE is live, non-GB institutions receive the honest no-data signal described above.
Companion fix: SBTi branch logic (Mode C)
A structurally identical issue was found in sbti.js: the scraper branched on sector='40', emitting only SBTI-DASHBOARD signals for financials and only SBTI-CORPORATE signals for non-financials. This meant UN-E1.3 and UN-E1.4 — both universal rules sourced from SBTI-CORPORATE — never received signals from any financial institution.
Fixed in the same cycle: sbti.js now always emits SBTI-CORPORATE signals (for the universal rules), and additionally emits SBTI-DASHBOARD signals for sector-40 institutions. Both branches now run for financials.
Post-fix verification (cycle 11, runs 9–13):
- All 4 UK financials (INST-0001–0004) now have UN-E1.3 and UN-E1.4 signals from SBTI-CORPORATE.
- Barclays (INST-0001): not found in SBTi database (confidence=0.5, boolean_value=false). Raw score unchanged: 21.1 pre- and post-fix. Coverage increased from 37% to 41%.
- INST-0009: now has UN-E1.3, UN-E1.4 (SBTI-CORPORATE, conf=0.5), and UN-S1.3 (UK-MSA, conf=0.0) signals. Raw score unchanged: 16.1. Coverage increased from 30% to 37%.
Design principle (addition to ADR-0010)
Universal rules sourced from geography- or sector-specific registers need a fallback chain documented at rule-definition time.
The universal-rule layer exists precisely to give every institution common comparison ground. A universal rule with a source that silently no-ops for a subset of institutions is an internal inconsistency — the rule fires universally but data coverage is bounded by source geography. Two outcomes are acceptable:
- Honest no-data: the source guard emits an explicit
confidence=0.0, boolean_value=false, extraction_ok=truesignal instead of returning[]. The absence is recorded, not hidden. - Fallback chain: a secondary source covers the institutions that the primary source misses. The rule table or a companion config records both sources and their applicability conditions.
Silent [] returns from guarded scrapers feeding universal rules are always wrong. They convert a "source doesn't apply" state into an invisible "no evaluation" state, which the coverage model misinterprets as missing coverage rather than confirmed absence.
Going forward, any new universal rule (applicable_sectors='ALL') whose source_id maps to a geographically or sectorally restricted scraper must document its fallback chain in the migration that seeds it. If no fallback exists yet, it must emit an honest no-data signal for out-of-scope institutions rather than returning [].
Related artefacts
docs/design/geographic-scoping-audit.md— full audit with three failure modes and v1.5 implications- Migration 016 (
016_scrape_skip.sql) —scrape_skiptable for country-guard skip records src/scrapers/ukmsa.js— country guard now writes skip record + returns no-data signal for UN-S1.3src/scrapers/ukgpg.js— country guard now writes skip record (UK-GPG has no universal rules)src/scrapers/sbti.js— SBTI-CORPORATE branch now runs for all institutions, not just non-financials