From c16a412cfd4d85417cd6f2e8afcbd09c224bf2eb Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Thu, 23 Jul 2026 22:06:52 -0700 Subject: [PATCH 1/5] Declare segmented research ledgers --- src/_data/research/ledger-manifest.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/_data/research/ledger-manifest.json diff --git a/src/_data/research/ledger-manifest.json b/src/_data/research/ledger-manifest.json new file mode 100644 index 0000000..a2bfd1f --- /dev/null +++ b/src/_data/research/ledger-manifest.json @@ -0,0 +1,10 @@ +{ + "sources": [ + "src/_data/research/sources.yml", + "src/_data/research/sources-2026-07-23.yml" + ], + "claims": [ + "src/_data/research/claims.yml", + "src/_data/research/claims-2026-07-23.yml" + ] +} From 1aba7af15438d0d857fe93bc13bf7309fdffb56d Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Thu, 23 Jul 2026 22:07:30 -0700 Subject: [PATCH 2/5] Add deeper Article Lab research sources --- src/_data/research/sources-2026-07-23.yml | 131 ++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 src/_data/research/sources-2026-07-23.yml diff --git a/src/_data/research/sources-2026-07-23.yml b/src/_data/research/sources-2026-07-23.yml new file mode 100644 index 0000000..3bee319 --- /dev/null +++ b/src/_data/research/sources-2026-07-23.yml @@ -0,0 +1,131 @@ +- id: doocy-tappis-2017-humanitarian-cash + title: "Cash-based approaches in humanitarian emergencies: a systematic review" + authors: "Shannon Doocy; Hannah Tappis" + year: 2017 + publication: "Campbell Systematic Reviews" + type: systematic review + doi: "10.4073/csr.2017.17" + url: "https://doi.org/10.4073/csr.2017.17" + reviewed_on: "2026-07-23" + relevance: "Reviews effectiveness, efficiency, and implementation evidence for cash transfers, vouchers, and in-kind assistance in humanitarian emergencies, including food-security outcomes and context-dependent delivery tradeoffs." + boundary: "The effectiveness evidence was sparse and generally low quality, with searches ending in November 2014; no transfer modality was universally superior across emergencies." + +- id: ng-et-al-2012-sdt-meta-analysis + title: "Self-Determination Theory Applied to Health Contexts: A Meta-Analysis" + authors: "Johan Y. Y. Ng; Nikos Ntoumanis; Cecilie Thøgersen-Ntoumani; Edward L. Deci; Richard M. Ryan; Joan L. Duda; Geoffrey C. Williams" + year: 2012 + publication: "Perspectives on Psychological Science 7(4):325-340" + type: peer-reviewed meta-analysis + doi: "10.1177/1745691612447309" + url: "https://doi.org/10.1177/1745691612447309" + reviewed_on: "2026-07-23" + relevance: "Synthesizes 184 independent data sets connecting practitioner autonomy support, psychological-need satisfaction, autonomous motivation, health behavior, and mental and physical health outcomes." + boundary: "The evidence is heterogeneous and concentrated in healthcare and health-promotion settings; it does not validate every duty in Article Two or make coercion effective elsewhere." + +- id: magana-et-al-2020-unpaid-caregivers-lmic + title: "Health outcomes of unpaid caregivers in low- and middle-income countries: A systematic review and meta-analysis" + authors: "Irene Magaña; Pablo Martínez; María-Soledad Loyola" + year: 2020 + publication: "Journal of Clinical Nursing 29(21-22):3950-3965" + type: systematic review and meta-analysis of observational studies + doi: "10.1111/jocn.15450" + url: "https://doi.org/10.1111/jocn.15450" + reviewed_on: "2026-07-23" + relevance: "Reviews 14 studies from Africa, Asia, and South America and finds that unpaid caregivers of people with ill-health were generally more anxious and depressed than noncaregivers, with important regional and gender variation." + boundary: "The evidence is observational, geographically sparse, and culturally heterogeneous; it does not show that care is intrinsically harmful or determine how necessary care should be shared." + +- id: rossetti-hilbe-2024-direct-reciprocity + title: "Direct reciprocity among humans" + authors: "Charlotte S. L. Rossetti; Christian Hilbe" + year: 2024 + publication: "Ethology" + type: peer-reviewed theory-and-evidence review + doi: "10.1111/eth.13407" + url: "https://doi.org/10.1111/eth.13407" + reviewed_on: "2026-07-23" + relevance: "Compares repeated-game theory with experiments involving human participants, finding that models often predict when cooperation occurs better than the particular reciprocal strategies people use." + boundary: "The reviewed experiments use stylized games and incentives; they do not establish real-world consent to retaliation or justify mirroring harmful conduct." + +- id: reiter-et-al-2018-reciprocity-crosstalk + title: "Crosstalk in concurrent repeated games impedes direct reciprocity and requires stronger levels of forgiveness" + authors: "Johannes G. Reiter; Christian Hilbe; David G. Rand; Krishnendu Chatterjee; Martin A. Nowak" + year: 2018 + publication: "Nature Communications 9:555" + type: peer-reviewed mathematical and simulation study + doi: "10.1038/s41467-017-02721-8" + url: "https://doi.org/10.1038/s41467-017-02721-8" + reviewed_on: "2026-07-23" + relevance: "Models how experience in one concurrent relationship can spill into another, spreading defection and making strict Tit-for-Tat brittle while bounded forgiveness can preserve cooperation." + boundary: "This is a formal model supported by simulations, not a direct field trial; forgiveness in a repeated game is not an instruction to remain exposed to abuse." + +- id: masson-waldron-1994-legal-contract-comprehension + title: "Comprehension of legal contracts by non-experts: Effectiveness of plain language redrafting" + authors: "Michael E. J. Masson; Mary Anne Waldron" + year: 1994 + publication: "Applied Cognitive Psychology 8(1):67-85" + type: peer-reviewed experiment + doi: "10.1002/acp.2350080107" + url: "https://doi.org/10.1002/acp.2350080107" + reviewed_on: "2026-07-23" + relevance: "Finds that simplified words and sentence structure improved non-experts' paraphrasing and question-answering about legal contracts." + boundary: "Absolute comprehension remained low and complex legal concepts still conflicted with prior beliefs; contract experiments do not establish comprehension of every law." + +- id: zietlow-et-al-2022-guardianship-capacity + title: "Guardianship: A medicolegal review for clinicians" + authors: "Kahli Zietlow; Leslie Dubin; Alethia Battles; Caroline Vitale" + year: 2022 + publication: "Journal of the American Geriatrics Society" + type: peer-reviewed medicolegal review + doi: "10.1111/jgs.17797" + url: "https://doi.org/10.1111/jgs.17797" + reviewed_on: "2026-07-23" + relevance: "Describes decision-making capacity as task-specific and dynamic, requiring understanding, appreciation, reasoning, and a consistent choice free from coercion, while emphasizing alternatives to and reassessment of guardianship." + boundary: "The review concerns United States clinical and guardianship practice, where state law varies; medical capacity is not identical to legal capacity or political adulthood." + +- id: woolley-et-al-2010-collective-intelligence + title: "Evidence for a collective intelligence factor in the performance of human groups" + authors: "Anita Williams Woolley; Christopher F. Chabris; Alex Pentland; Nada Hashmi; Thomas W. Malone" + year: 2010 + publication: "Science 330(6004):686-688" + type: peer-reviewed group experiments + doi: "10.1126/science.1193147" + url: "https://doi.org/10.1126/science.1193147" + reviewed_on: "2026-07-23" + relevance: "In two studies with 699 people working in groups of two to five, identifies a general group-performance factor associated with social sensitivity and more equal conversational turn-taking." + boundary: "The experiments used small groups and selected tasks; the proposed predictors were challenged by later replication work and do not validate any fixed circle size or authority structure." + +- id: bates-gupta-2017-group-intelligence + title: "Smart groups of smart people: Evidence for IQ as the origin of collective intelligence in the performance of human groups" + authors: "Timothy C. Bates; Shivani Gupta" + year: 2017 + publication: "Intelligence 60:46-56" + type: peer-reviewed replication and model test + doi: "10.1016/j.intell.2016.11.004" + url: "https://doi.org/10.1016/j.intell.2016.11.004" + reviewed_on: "2026-07-23" + relevance: "Across three studies with 312 people, reports that individual cognitive ability explained most group-performance differences while gender balance, turn-taking, and social sensitivity did not explain the latent group factor." + boundary: "These studies challenge rather than erase the original findings; they use small experimental groups and do not establish that interaction processes are irrelevant in real institutions." + +- id: bertocchi-et-al-2023-standardized-terminologies + title: "Impact of standardized nursing terminologies on patient and organizational outcomes: A systematic review and meta-analysis" + authors: "Luca Bertocchi; Angelo Dante; Carmen La Cerra; Vittorio Masotta; Alessia Marcotullio; Dorothy Jones; Cristina Petrucci; Loreto Lancia" + year: 2023 + publication: "Journal of Nursing Scholarship 55(6):1126-1153" + type: systematic review and meta-analysis + doi: "10.1111/jnu.12894" + url: "https://doi.org/10.1111/jnu.12894" + reviewed_on: "2026-07-23" + relevance: "Reviews 53 reports on recognized standardized nursing terminologies and finds associations or improvements across documentation, prediction, knowledge, self-efficacy, readmission, and other patient or organizational outcomes." + boundary: "GRADE certainty was very low to low, most studies were observational, and terminology was often embedded in larger interventions; causal effects remain uncertain." + +- id: stacey-et-al-2024-decision-aids + title: "Decision aids for people facing health treatment or screening decisions" + authors: "Dawn Stacey et al." + year: 2024 + publication: "Cochrane Database of Systematic Reviews 2024(1):CD001431" + type: Cochrane systematic review of randomized controlled trials + doi: "10.1002/14651858.CD001431.pub6" + url: "https://doi.org/10.1002/14651858.CD001431.pub6" + reviewed_on: "2026-07-23" + relevance: "Synthesizes 209 trials with 107,698 adults and finds that decision aids increase knowledge, accurate risk perceptions, active participation, and informed values-congruent choices without increasing decision regret." + boundary: "The review concerns health treatment and screening decisions, with evidence current to March 2022; adherence, resource effects, and representation of resource-limited countries remain incomplete." From fc8ebc3984c055640913941e64c070227dbd7d71 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Thu, 23 Jul 2026 22:07:50 -0700 Subject: [PATCH 3/5] Attach deeper evidence to Article Labs --- src/_data/research/claims-2026-07-23.yml | 82 ++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 src/_data/research/claims-2026-07-23.yml diff --git a/src/_data/research/claims-2026-07-23.yml b/src/_data/research/claims-2026-07-23.yml new file mode 100644 index 0000000..1043bda --- /dev/null +++ b/src/_data/research/claims-2026-07-23.yml @@ -0,0 +1,82 @@ +- id: article-one-assistance-modality + article: rights-and-definitions-of-the-way.article-one + stance: mixed + status: systematic-review + claim: "Cash, vouchers, and in-kind food can each support emergency food security, while their relative effectiveness and efficiency depend on markets, security, delivery capacity, recipient selection, and the outcome being optimized." + source_ids: + - doocy-tappis-2017-humanitarian-cash + limitation: "The review found sparse, generally low-quality effectiveness evidence through November 2014 and does not establish a universal assistance modality, contribution rule, or justified exclusion." + +- id: article-two-autonomy-meta-analysis + article: rights-and-definitions-of-the-way.article-two + stance: support + status: meta-analytic + claim: "Across health contexts, autonomy support, psychological-need satisfaction, and autonomous motivation are positively related to sustained health behavior and beneficial mental and physical health outcomes." + source_ids: + - ng-et-al-2012-sdt-meta-analysis + limitation: "The meta-analysis concerns heterogeneous healthcare and health-promotion settings; it does not prove every duty in Article Two or make coercion compatible with autonomous motivation." + +- id: article-two-care-duty-burden + article: rights-and-definitions-of-the-way.article-two + stance: dissent + status: meta-analytic-limit + claim: "Necessary unpaid care can transfer anxiety and depression risk to caregivers, so survival duties cannot be allocated as though caregivers possess unlimited time, health, or support." + source_ids: + - magana-et-al-2020-unpaid-caregivers-lmic + limitation: "The review includes 14 observational studies across diverse low- and middle-income settings; it does not show that caregiving is intrinsically harmful or prescribe one allocation system." + +- id: article-three-forgiving-reciprocity + article: rights-and-definitions-of-the-way.article-three + stance: mixed + status: theory-evidence-synthesis + claim: "Repeated interaction can sustain cooperative reciprocity, but strict act-for-act retaliation is error-sensitive; concurrent social crosstalk can spread defection and require bounded forgiveness or other error-correcting strategies." + source_ids: + - rossetti-hilbe-2024-direct-reciprocity + - reiter-et-al-2018-reciprocity-crosstalk + limitation: "The evidence comes mainly from stylized games, mathematical models, and simulations; it neither establishes consent to retaliation nor instructs anyone to forgive or remain exposed to abuse." + +- id: article-four-plain-language-boundary + article: rights-and-definitions-of-the-way.article-four + stance: mixed + status: experimental + claim: "Plain-language redrafting can improve non-expert comprehension of legal contracts, but language simplification alone leaves substantial misunderstanding when complex concepts conflict with prior knowledge and beliefs." + source_ids: + - masson-waldron-1994-legal-contract-comprehension + limitation: "The controlled study concerns legal contracts rather than all law; it supports instruction and comprehension checks, not the assumption that publication or simplified wording guarantees knowledge." + +- id: article-five-task-specific-capacity + article: rights-and-definitions-of-the-way.article-five + stance: limit + status: medicolegal-review + claim: "Decision-making capacity is ordinarily task-specific and dynamic, requiring understanding, appreciation, reasoning, and a consistent choice free from coercion; global status tests can erase retained capacities and autonomy." + source_ids: + - zietlow-et-al-2022-guardianship-capacity + limitation: "The review concerns United States clinical and guardianship practice, not political adulthood; medical decision-making capacity and equal legal status remain distinct questions." + +- id: article-six-collective-intelligence-dispute + article: rights-and-definitions-of-the-way.article-six + stance: mixed + status: contested-replication + claim: "Small groups show stable differences in collective performance, but experiments conflict over whether conversational equality and social sensitivity or the cognitive ability of members best explains those differences." + source_ids: + - woolley-et-al-2010-collective-intelligence + - bates-gupta-2017-group-intelligence + limitation: "Both research programs use small experimental groups and selected tasks; their disagreement does not validate twelve-person circles, singular emergency leadership, or any authority derived from violence." + +- id: article-seven-standard-terminology-outcomes + article: rights-and-definitions-of-the-way.article-seven + stance: mixed + status: low-certainty-meta-analysis + claim: "Shared professional terminology can improve documentation, coordination, prediction, knowledge, self-efficacy, and some outcomes, while current causal evidence remains low-certainty and methodologically heterogeneous." + source_ids: + - bertocchi-et-al-2023-standardized-terminologies + limitation: "The review concerns recognized nursing terminologies usually embedded in larger interventions; it does not establish that imposed definitions are neutral or sufficient in ordinary conversation." + +- id: article-eight-decision-aids + article: rights-and-definitions-of-the-way.article-eight + stance: support + status: high-certainty-review + claim: "Decision aids that make options explicit and communicate benefits, harms, probabilities, and personal values help adults make more informed, active, values-congruent health choices without increasing decision regret." + source_ids: + - stacey-et-al-2024-decision-aids + limitation: "The review concerns health treatment and screening decisions; it does not create a universal consent standard, and evidence on adherence, resource effects, and resource-limited settings remains incomplete." From febc12cafee4f71b9335217cade52239ab42877b Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Thu, 23 Jul 2026 22:08:13 -0700 Subject: [PATCH 4/5] Load segmented research ledgers --- src/_data/research_data.js | 44 +++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/src/_data/research_data.js b/src/_data/research_data.js index 4ea40fd..ce2c5d0 100644 --- a/src/_data/research_data.js +++ b/src/_data/research_data.js @@ -5,27 +5,27 @@ import yaml from 'js-yaml'; // id: article_lab_research_data_adapter // module_name: research_data // module_kind: adapter -// summary: Loads the reviewed research source and claim ledgers into one explicit Eleventy global-data object. +// summary: Loads manifest-declared reviewed research source and claim ledgers into one explicit Eleventy global-data object. // owner: Erin Spencer // public_surface: research_data.sources, research_data.claims -// internal_surface: readYamlList +// internal_surface: validateLedgerPaths, readYamlList, readYamlLedgers // auth_boundary: none -// storage_boundary: read +// storage_boundary: read the repository-owned research manifest and its declared YAML ledgers // network_boundary: none // user_data_boundary: none // admin_only: false // tests: tests/research-ledger.test.mjs, tests/generated-site.test.mjs // rollout: loaded automatically by Eleventy from src/_data/research_data.js -// rollback: restore direct template access after proving nested YAML data resolution +// rollback: restore direct two-file reads and remove the manifest-declared tranche files // === END MODULE_BUILD === -// Usage: reference `research_data.sources` and `research_data.claims` in Nunjucks templates. -// Limits: this adapter exposes reviewed ledger content only; it does not infer stance, truth, or source relevance. +// Usage: add a repository-local YAML ledger path to ledger-manifest.json, then reference `research_data.sources` and `research_data.claims` in Nunjucks templates. +// Limits: this adapter exposes reviewed ledger content only; it does not infer stance, truth, source relevance, or evidentiary weight. // === BOUNDARIES === // id: article_lab_research_data_storage_boundary -// summary: Reads two repository-owned YAML ledgers during static-site generation and returns parsed arrays. +// summary: Reads allowlisted repository-local YAML ledgers during static-site generation and returns parsed arrays. // auth_boundary: none -// storage_boundary: read +// storage_boundary: read beneath src/_data/research only // network_boundary: none // user_data_boundary: none // admin_only: false @@ -35,16 +35,40 @@ import yaml from 'js-yaml'; // owner: Erin Spencer // === END BOUNDARIES === +const manifestPath = 'src/_data/research/ledger-manifest.json'; +const ledgerPathPattern = /^src\/_data\/research\/[a-z0-9][a-z0-9.-]*\.yml$/; + +function validateLedgerPaths(paths, kind) { + if (!Array.isArray(paths) || paths.length === 0) throw new TypeError(`${kind} ledger manifest must contain at least one path`); + if (new Set(paths).size !== paths.length) throw new TypeError(`${kind} ledger manifest paths must be unique`); + for (const path of paths) { + if (typeof path !== 'string' || !ledgerPathPattern.test(path)) { + throw new TypeError(`${kind} ledger path must remain beneath src/_data/research and end in .yml: ${String(path)}`); + } + } + return paths; +} + async function readYamlList(path) { const parsed = yaml.load(await readFile(path, 'utf8')); if (!Array.isArray(parsed)) throw new TypeError(`${path} must contain a YAML list`); return parsed; } +async function readYamlLedgers(paths, kind) { + const validatedPaths = validateLedgerPaths(paths, kind); + const ledgers = await Promise.all(validatedPaths.map(readYamlList)); + return ledgers.flat(); +} + export default async function researchData() { + const manifest = JSON.parse(await readFile(manifestPath, 'utf8')); + if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest)) throw new TypeError(`${manifestPath} must contain a JSON object`); + const [sources, claims] = await Promise.all([ - readYamlList('src/_data/research/sources.yml'), - readYamlList('src/_data/research/claims.yml') + readYamlLedgers(manifest.sources, 'source'), + readYamlLedgers(manifest.claims, 'claim') ]); + return { sources, claims }; } From f78872d13f9f261aa4929ca461379e2d88519611 Mon Sep 17 00:00:00 2001 From: Erin Spencer Date: Thu, 23 Jul 2026 22:08:44 -0700 Subject: [PATCH 5/5] Validate segmented research depth --- tests/research-ledger.test.mjs | 49 +++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/tests/research-ledger.test.mjs b/tests/research-ledger.test.mjs index 9988dd7..18f1adc 100644 --- a/tests/research-ledger.test.mjs +++ b/tests/research-ledger.test.mjs @@ -1,10 +1,12 @@ -// Usage: run through `npm test`; every Rights Article must retain at least one reviewed support and dissent claim, while mixed and limit records preserve conditional evidence. -// Evidence boundary: validates provenance and coverage structure, not the truth of every source claim or application. +// Usage: run through `npm test`; every manifest-declared research ledger must parse and every Rights Article must retain reviewed support and dissent. +// Evidence boundary: validates provenance, segmentation, and coverage structure, not the truth of every source claim or application. import test from 'node:test'; import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; import yaml from 'js-yaml'; +const manifestPath = 'src/_data/research/ledger-manifest.json'; +const ledgerPathPattern = /^src\/_data\/research\/[a-z0-9][a-z0-9.-]*\.yml$/; const requiredDomains = [ 'Medical', 'Construction', @@ -19,30 +21,51 @@ const requiredDomains = [ 'Community governance' ]; +async function readYamlLedgers(paths, kind) { + assert.ok(Array.isArray(paths) && paths.length > 0, `${kind} ledger manifest must contain paths`); + assert.equal(new Set(paths).size, paths.length, `${kind} ledger manifest paths must be unique`); + + const ledgers = []; + for (const path of paths) { + assert.equal(typeof path, 'string'); + assert.match(path, ledgerPathPattern, `${kind} ledger path must remain beneath src/_data/research`); + const parsed = yaml.load(await readFile(path, 'utf8')); + assert.ok(Array.isArray(parsed) && parsed.length > 0, `${path} must contain a non-empty YAML list`); + ledgers.push(parsed); + } + return ledgers.flat(); +} + test('research ledgers parse and claims resolve to reviewed sources', async () => { - const sources = yaml.load(await readFile('src/_data/research/sources.yml', 'utf8')); - const claims = yaml.load(await readFile('src/_data/research/claims.yml', 'utf8')); - const articleLab = JSON.parse(await readFile('src/_data/article_lab.json', 'utf8')); - assert.ok(Array.isArray(sources) && sources.length > 0); - assert.ok(Array.isArray(claims) && claims.length > 0); + const manifest = JSON.parse(await readFile(manifestPath, 'utf8')); + assert.ok(manifest && typeof manifest === 'object' && !Array.isArray(manifest)); + + const [sources, claims, articleLab] = await Promise.all([ + readYamlLedgers(manifest.sources, 'source'), + readYamlLedgers(manifest.claims, 'claim'), + readFile('src/_data/article_lab.json', 'utf8').then(JSON.parse) + ]); + + assert.ok(sources.length >= 32, 'the reviewed source corpus must not regress below the current evidence floor'); + assert.ok(claims.length >= 30, 'the reviewed claim corpus must not regress below the current evidence floor'); assert.ok(Array.isArray(articleLab) && articleLab.length === 8); const sourceIds = new Set(sources.map(source => source.id)); const labUnitIds = new Set(articleLab.map(record => record.unit_id)); - assert.equal(sourceIds.size, sources.length, 'source ids must be unique'); - assert.equal(new Set(claims.map(claim => claim.id)).size, claims.length, 'claim ids must be unique'); + assert.equal(sourceIds.size, sources.length, 'source ids must be unique across all ledgers'); + assert.equal(new Set(claims.map(claim => claim.id)).size, claims.length, 'claim ids must be unique across all ledgers'); assert.equal(labUnitIds.size, 8, 'each Rights article must have one Lab record'); for (const source of sources) { - assert.ok(source.title && source.url && source.reviewed_on && source.boundary); + assert.ok(source.id && source.title && source.authors && source.year && source.publication && source.type); + assert.ok(source.url && source.reviewed_on && source.relevance && source.boundary); } for (const claim of claims) { assert.ok(['support', 'dissent', 'limit', 'mixed'].includes(claim.stance)); - assert.ok(claim.status && claim.claim); + assert.ok(claim.id && claim.status && claim.claim && claim.limitation); assert.ok(labUnitIds.has(claim.article), `claim ${claim.id} is not attached to a Rights Article Lab record`); assert.ok(Array.isArray(claim.source_ids) && claim.source_ids.length > 0); for (const sourceId of claim.source_ids) assert.ok(sourceIds.has(sourceId), `unknown source ${sourceId}`); - assert.ok(claim.limitation); } for (const record of articleLab) { @@ -52,7 +75,7 @@ test('research ledgers parse and claims resolve to reviewed sources', async () = assert.ok(Array.isArray(record.best_practices) && record.best_practices.length >= 4); assert.deepEqual(Object.keys(record.applications), requiredDomains, `${record.unit_id} must preserve the shared domain order`); const articleClaims = claims.filter(claim => claim.article === record.unit_id); - assert.ok(articleClaims.length > 0, `${record.unit_id} needs reviewed research contact`); + assert.ok(articleClaims.length >= 3, `${record.unit_id} needs more than a minimal support-dissent pair`); assert.ok(articleClaims.some(claim => claim.stance === 'support'), `${record.unit_id} needs reviewed support`); assert.ok(articleClaims.some(claim => claim.stance === 'dissent'), `${record.unit_id} needs reviewed dissent`); }