diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index d08a49e..e58a7c5 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -24,10 +24,21 @@ jobs: run: npm ci - name: Build, validate, and test - run: npm run check + run: | + set -o pipefail + npm run check 2>&1 | tee check.log env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Preserve check failure log + if: failure() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7, node24 + with: + name: check-failure-${{ github.sha }} + path: check.log + retention-days: 7 + if-no-files-found: error + - name: Install Chromium release dependency run: npx playwright install --with-deps chromium diff --git a/docs/research-method.md b/docs/research-method.md index 5375da4..80d3aa4 100644 --- a/docs/research-method.md +++ b/docs/research-method.md @@ -1,3 +1,18 @@ # Research method Sources and claims are stored in `src/_data/research`. Stance classification is editorial review, not automated metadata inference. Missing support or dissent must render as a documented `hmmm` gap. + +## Article Lab contact structure + +The eight Rights Article Labs use `src/_data/article_lab.json`. Every record must include: + +- a reductio ad absurdum test in both directions plus a bounded reading; +- at least four worst practices and four best practices; +- applications for medical, construction, engineering, agriculture, jurisprudence, transportation and distribution, child craft, information systems, emergency response, hospitality and sanitation, and community governance; +- at least one reviewed claim linked to a source with an explicit evidence boundary. + +## Usage guidance + +Add or revise operational applications in `article_lab.json`. Add research evidence separately in `sources.yml` and `claims.yml`; do not place an uncited empirical claim inside an application paragraph. Run `npm test`, `npm run build`, `npm run test:generated`, and `npm run test:browser` before publication. + +An application is a bounded hypothesis about how an Article might constrain practice in a domain. It does not supersede domain standards, professional duties, law, safety rules, or the canonical text. Reductio sections deliberately test destructive overextension and destructive absolute rejection; neither is presented as the endorsed reading. diff --git a/src/_data/article_lab.json b/src/_data/article_lab.json new file mode 100644 index 0000000..85e65ee --- /dev/null +++ b/src/_data/article_lab.json @@ -0,0 +1,274 @@ +[ + { + "unit_id": "rights-and-definitions-of-the-way.article-one", + "public_title": "Article One — Contribution without contempt", + "ad_absurdum": { + "overextension": "If ‘so all may eat’ is treated as an unlimited claim on finite stores, contribution and stewardship disappear; the common table is consumed until nobody can eat.", + "counter_overextension": "If contribution is made an absolute precondition for food, incapacity, scarcity, caregiving, injury, childhood, and temporary dependence become punishable by hunger.", + "boundary": "Provide the survival floor first, then distinguish inability, refusal, fraud, and active harm through evidence, proportion, and review." + }, + "worst_practices": [ + "Require degrading proof of deservingness before meeting an immediate survival need.", + "Treat disability, exhaustion, caregiving, unemployment, or scarcity as deliberate refusal.", + "Let the person controlling supplies define contribution and harm without appeal.", + "Confuse equal human worth with identical allocation regardless of need or resource limits." + ], + "best_practices": [ + "Stabilize hunger or immediate danger before conducting eligibility or accountability review.", + "Separate need, capacity, contribution, refusal, and harmful conduct in the record.", + "Publish resource limits, allocation rules, exceptions, and an appeal path.", + "Use the least destructive response that protects the shared capacity to provide." + ], + "applications": { + "Medical": "Provide stabilizing care before billing, compliance, or character judgments; determine whether nonparticipation reflects incapacity, fear, access barriers, or refusal.", + "Construction": "Treat water, sanitation, rest, fall protection, and protective equipment as a floor while assigning work according to demonstrated capacity.", + "Engineering": "Reserve minimum safe operating resources before optimization and design graceful degradation so the least powerful user is not the first excluded.", + "Agriculture": "Protect seed, water, soil, feed, and subsistence reserves before market allocation; distinguish crop failure from neglect and extraction.", + "Jurisprudence": "Do not condition food, shelter, emergency medicine, or access to process on confession, status performance, or inability to pay.", + "Transportation and distribution": "Publish priority rules for scarce deliveries, preserve emergency stock and cold chain, and record why loads were rerouted or refused.", + "Child craft": "Meals, safety, affection, and basic learning materials remain unconditional; contribution is age-appropriate participation, not payment for care.", + "Information systems": "Maintain a minimum service level, accessible recovery path, and fair rate limits before premium optimization or anti-abuse escalation.", + "Emergency response": "Triage life threats first, then document conduct, capacity, and resource claims for later accountability.", + "Hospitality and sanitation": "Guarantee potable water, toilets, handwashing, waste removal, and basic food safety before aesthetic upgrades.", + "Community governance": "Maintain a visible survival floor and a transparent contribution ledger that includes care, maintenance, teaching, and risk-bearing work." + } + }, + { + "unit_id": "rights-and-definitions-of-the-way.article-two", + "public_title": "Article Two — Freedom without abandonment", + "ad_absurdum": { + "overextension": "If ‘do nothing against your will’ means no obligation can ever survive reluctance, essential care, maintenance, sanitation, and teaching are abandoned whenever they become difficult.", + "counter_overextension": "If every necessary task creates an enforceable duty on any available person, necessity becomes a universal excuse for forced labor.", + "boundary": "Make necessary work visible, preserve refusal and exit, develop competence, distribute burdens, and escalate only when a specific preventable harm cannot otherwise be covered." + }, + "worst_practices": [ + "Rename coercion as teamwork, professionalism, family duty, or emergency whenever consent is inconvenient.", + "Hide essential labor until the same low-status person repeatedly absorbs it.", + "Treat trauma, poverty, dependence, or threat as irrelevant to whether a choice is voluntary.", + "Assign responsibility without tools, time, authority, training, or a safe way to decline." + ], + "best_practices": [ + "List the necessary tasks, capacities, risks, and unclaimed burdens before assigning people.", + "Use voluntary selection, rotation, mutual aid, training, and compensation before compulsion.", + "Preserve a meaningful refusal path and record the actual consequence of an uncovered task.", + "Separate immediate stabilization from redesign of the system producing repeated emergencies." + ], + "applications": { + "Medical": "Use informed choice, shared decision-making, team role clarity, and escalation paths while ensuring urgent symptoms are not ignored.", + "Construction": "Make task hazards and qualifications visible, allow stop-work authority, rotate undesirable work, and correct missing tools before blaming labor.", + "Engineering": "Define essential maintenance ownership, on-call limits, fallback capacity, and handoff requirements before failure.", + "Agriculture": "Plan labor, water, animal care, harvest, and repair duties around seasonal necessity while protecting rest, refusal, and contingency coverage.", + "Jurisprudence": "Use narrowly tailored civic duties with notice, competence support, exemptions, review, and proportional consequences.", + "Transportation and distribution": "Publish essential-route coverage, fatigue limits, relief crews, and refusal procedures for unsafe loads or conditions.", + "Child craft": "Teach necessary household and social skills through participation, modeling, choice within boundaries, and developmentally appropriate responsibility.", + "Information systems": "Define service ownership, incident rotation, maintenance windows, and user-impact priorities with sustainable staffing.", + "Emergency response": "Use predeclared roles, mutual-aid agreements, relief cycles, and lawful emergency authority with after-action review.", + "Hospitality and sanitation": "Make cleaning, food safety, laundry, and waste work visible, staffed, equipped, compensated, and rotatable.", + "Community governance": "Maintain a public task board showing what survival work exists, what is covered, what is unclaimed, and what support would make participation possible." + } + }, + { + "unit_id": "rights-and-definitions-of-the-way.article-three", + "public_title": "Article Three — Speech as demonstrated consent", + "ad_absurdum": { + "overextension": "If every hostile word authorizes identical treatment in return, one insult becomes a license for an escalating chain of retaliation.", + "counter_overextension": "If no conduct may shape the response it receives, chronic intimidation and manipulation gain protection from proportionate boundaries.", + "boundary": "Treat speech and conduct as evidence about interaction—not blanket consent. Clarify the mode, respond proportionately, preserve non-escalatory exits, and distinguish boundary-setting from revenge." + }, + "worst_practices": [ + "Infer consent to violence, humiliation, sex, punishment, or permanent exclusion from tone or prior conduct.", + "Mirror aggression automatically and call retaliation reciprocity.", + "Use politeness demands to silence accurate warnings, anger, grief, or dissent.", + "Judge wording without accounting for disability, language, culture, trauma, urgency, or power." + ], + "best_practices": [ + "Name the interaction mode: question, request, command, warning, accusation, joke, negotiation, or emergency direction.", + "Confirm meaning and desired response before escalating ambiguous speech.", + "Use the smallest proportionate boundary that stops harm and keeps repair possible.", + "Record threats, commands, consent, refusals, and handoffs in high-consequence settings." + ], + "applications": { + "Medical": "Use closed-loop communication, teach-back, escalation phrases, and explicit consent; treat distress speech as clinical information rather than permission to retaliate.", + "Construction": "Standardize stop-work calls, hazard warnings, hand signals, read-backs, and supervisor acknowledgment.", + "Engineering": "Label requirements, assumptions, objections, decisions, and unresolved risks; separate critique of a design from attack on a person.", + "Agriculture": "Use clear animal-handling, machinery, chemical, weather, and harvest signals across language and literacy differences.", + "Jurisprudence": "Distinguish protected speech, threat, instruction, consent, confession, and coercion with context and evidentiary standards.", + "Transportation and distribution": "Use standardized dispatch, load, route, exception, and emergency messages with read-back for consequential changes.", + "Child craft": "Teach children to name feelings, boundaries, requests, refusals, and repair while adults retain responsibility for proportional response.", + "Information systems": "Separate alerts, warnings, errors, approvals, and destructive confirmations; preserve logs and explicit user intent.", + "Emergency response": "Use plain command language, role identifiers, repeat-backs, and explicit transfer of command.", + "Hospitality and sanitation": "Standardize allergy, contamination, shortage, spill, and harassment reporting with no-retaliation acknowledgment.", + "Community governance": "Publish conversation rules that protect dissent, require definition of serious accusations, and distinguish debate from threat." + } + }, + { + "unit_id": "rights-and-definitions-of-the-way.article-four", + "public_title": "Article Four — Law as teachable duty", + "ad_absurdum": { + "overextension": "If every person must fully know every rule before acting, lawful participation becomes impossible and specialists monopolize ordinary life.", + "counter_overextension": "If institutions have no duty to teach the rules they enforce, secret, shifting, or unintelligible law becomes a trap.", + "boundary": "Teach the rules relevant to a person’s role and risk in language they can use; preserve notice, questions, examples, version history, and a defense when the system failed to make the duty knowable." + }, + "worst_practices": [ + "Punish first and explain the governing rule afterward.", + "Publish rules only in technical language, inaccessible formats, or scattered locations.", + "Change requirements silently while continuing enforcement.", + "Treat a signature, checkbox, or posted notice as proof of comprehension." + ], + "best_practices": [ + "Use plain language, examples, nonexamples, translated and accessible formats.", + "Require teach-back or demonstrated use for high-consequence duties.", + "Version rules, announce changes, and preserve the rule that applied at the time.", + "Create a question, correction, and appeal path before escalating punishment." + ], + "applications": { + "Medical": "Explain diagnosis, options, risks, discharge duties, medication use, and return precautions in usable language with teach-back.", + "Construction": "Teach site rules through orientation, demonstration, signage, toolbox talks, and supervisor verification.", + "Engineering": "Make standards, interfaces, assumptions, tolerances, change control, and safety constraints available at the point of work.", + "Agriculture": "Teach chemical, animal, machinery, water, labor, and food-safety rules in the languages and media workers actually use.", + "Jurisprudence": "Provide notice of charges, applicable rules, process, consequences, representation, and appeal in plain language.", + "Transportation and distribution": "Train and verify route, load, hours, dangerous-goods, customs, and exception procedures before assignment.", + "Child craft": "State boundaries and reasons in developmentally appropriate language, model them, and revisit them as capacity grows.", + "Information systems": "Put permissions, data use, security duties, destructive actions, and recovery steps where decisions occur.", + "Emergency response": "Use preincident training, quick-reference job aids, briefings, and just-in-time instruction under a common command vocabulary.", + "Hospitality and sanitation": "Teach food temperatures, allergens, cleaning chemistry, exposure response, and reporting through demonstration and visible job aids.", + "Community governance": "Publish rules, definitions, meeting procedure, decision authority, records, and remedies in one accessible place." + } + }, + { + "unit_id": "rights-and-definitions-of-the-way.article-five", + "public_title": "Article Five — Adulthood as demonstrated competence", + "ad_absurdum": { + "overextension": "If a single competence test defines adulthood everywhere, one institution can erase adult standing through cultural bias, disability exclusion, or irrelevant performance.", + "counter_overextension": "If age or title alone establishes competence, people may wield consequential authority without the skills to avoid foreseeable harm.", + "boundary": "Assess competence by field, task, context, and consequence using multiple demonstrations, support, accommodations, transparent criteria, and periodic reevaluation." + }, + "worst_practices": [ + "Use one test, one language, one body type, or one educational pathway as the universal adult standard.", + "Confuse credentials, confidence, seniority, wealth, or obedience with competence.", + "Make failure permanent or hide what successful demonstration requires.", + "Remove support in order to test independence and then label predictable harm incapacity." + ], + "best_practices": [ + "Define observable field-specific competencies and the harms they are meant to prevent.", + "Allow portfolios, simulation, supervised practice, oral, written, physical, and assistive demonstrations as appropriate.", + "Provide instruction, accommodations, retesting, and bounded scopes of practice.", + "Reevaluate competence when the task, environment, technology, health, or consequence changes." + ], + "applications": { + "Medical": "Use role-specific competencies, supervised practice, continuing assessment, and scope limits while incorporating patient-centred communication and contextual functioning.", + "Construction": "Verify task-specific skills for equipment, fall protection, excavation, electrical work, lifting, and emergency response.", + "Engineering": "Require traceable design judgment, review, testing, failure analysis, and domain-specific authorization.", + "Agriculture": "Demonstrate seasonal, machinery, animal, soil, water, chemical, preservation, and market competencies in context.", + "Jurisprudence": "Separate legal capacity, task competence, representation needs, and authority; use periodic, contextual evaluation rather than global status labels.", + "Transportation and distribution": "Verify vehicle, route, load, fatigue, documentation, maintenance, and emergency competencies by role.", + "Child craft": "Use developmental progression: model, practice, supervised demonstration, expanding autonomy, and revisable responsibility.", + "Information systems": "Use least privilege tied to demonstrated operational, security, privacy, and recovery competence.", + "Emergency response": "Credential roles before incidents, verify perishable skills, and assign authority only within demonstrated capability.", + "Hospitality and sanitation": "Recognize food safety, cleaning chemistry, infection control, de-escalation, maintenance, and guest-care competencies as skilled work.", + "Community governance": "Require demonstrated comprehension of duties, conflicts, records, budgets, consent, and consequences before granting public authority." + } + }, + { + "unit_id": "rights-and-definitions-of-the-way.article-six", + "public_title": "Article Six — Authority as burden", + "ad_absurdum": { + "overextension": "If authority is justified whenever force can impose an outcome, successful violence becomes self-legitimating tyranny.", + "counter_overextension": "If nobody may hold bounded authority even during imminent danger, coordination collapses and the most forceful unofficial actor governs anyway.", + "boundary": "Name who may decide, by what selection, for which scope, for how long, with what records, relief, oversight, liability, and transfer of authority." + }, + "worst_practices": [ + "Declare a permanent emergency or let temporary command expand into ordinary governance.", + "Select authority opaquely, by confidence, proximity to force, or personal loyalty.", + "Hide decisions, casualties, exceptions, and conflicts from later review.", + "Glorify decisiveness while treating doubt, humor, consultation, or relief as weakness." + ], + "best_practices": [ + "Predeclare scope, triggers, succession, limits, and termination conditions.", + "Separate command authority from investigation, review, and adjudication.", + "Log material decisions and preserve challenge, whistleblowing, and after-action review.", + "Rotate, relieve, support, and hold the authority-bearer accountable for foreseeable misuse." + ], + "applications": { + "Medical": "Clarify attending, nursing, specialist, patient, surrogate, ethics, and emergency decision authority with escalation and handoff.", + "Construction": "Name competent persons, stop-work authority, lift directors, safety leads, and incident command before hazardous work.", + "Engineering": "Assign design authority, independent review, change approval, safety sign-off, and rollback ownership.", + "Agriculture": "Define authority for animal emergencies, chemical incidents, fire, water allocation, harvest decisions, and equipment shutdown.", + "Jurisprudence": "Constrain coercive authority through jurisdiction, evidence, hearing, reasons, appeal, recusal, and liability.", + "Transportation and distribution": "Define dispatch, captain, driver, maintenance, loadmaster, customs, and emergency authority with explicit handoff.", + "Child craft": "Adults carry protective authority as a burden bounded by development, explanation, proportionality, and the child’s growing agency.", + "Information systems": "Use scoped administrative roles, dual control for destructive actions, immutable logs, incident command, and timely revocation.", + "Emergency response": "Apply common command, span of control, unified coordination, transfer briefings, resource tracking, and demobilization.", + "Hospitality and sanitation": "Name who can close service, discard food, isolate contamination, remove a dangerous person, or summon emergency help.", + "Community governance": "Select bounded decision-makers through visible process, record mandate and dissent, and require periodic return of authority." + } + }, + { + "unit_id": "rights-and-definitions-of-the-way.article-seven", + "public_title": "Article Seven — Definitions before governance", + "ad_absurdum": { + "overextension": "If every word must be finally defined before conversation begins, discussion never starts and living language is frozen by gatekeepers.", + "counter_overextension": "If consequential terms never need definition, power can change their meaning midstream and make agreement, consent, or accountability impossible.", + "boundary": "Define the terms that control rights, duties, evidence, thresholds, and outcomes; include examples, exclusions, versioning, and a visible path for principled disagreement." + }, + "worst_practices": [ + "Use dictionary selection as an ambush after the other party has relied on a different meaning.", + "Let the most powerful participant define contested terms unilaterally.", + "Hide value judgments inside apparently neutral technical definitions.", + "Demand exhaustive definition of ordinary speech to delay or derail action." + ], + "best_practices": [ + "Identify which terms are load-bearing for the present decision.", + "State scope, examples, nonexamples, thresholds, and who may revise the definition.", + "Distinguish descriptive, technical, legal, moral, and local senses.", + "Record dissent and test whether different definitions would change the outcome." + ], + "applications": { + "Medical": "Define diagnosis, risk, benefit, success, capacity, emergency, standard care, and patient goals before consequential decisions.", + "Construction": "Define competent person, qualified person, acceptable condition, completion, defect, hazard, and stop-work threshold in contract and field use.", + "Engineering": "Use controlled vocabularies, units, interface contracts, requirement levels, assumptions, and acceptance criteria.", + "Agriculture": "Define organic, regenerative, humane, drought, pest threshold, yield, soil health, water right, and contamination for the local system.", + "Jurisprudence": "Define elements, burdens, standards, jurisdiction, harm, consent, reasonableness, and remedy before applying sanctions.", + "Transportation and distribution": "Define delivered, accepted, damaged, delayed, hazardous, perishable, secure, custody, and transfer timestamps.", + "Child craft": "Define family rules with concrete examples and revisit meanings as language and developmental capacity change.", + "Information systems": "Adopt explicit requirement words, schemas, threat definitions, severity levels, data ownership, availability targets, and done criteria.", + "Emergency response": "Use common terminology for command, resources, locations, priorities, triage, evacuation, and status.", + "Hospitality and sanitation": "Define clean, sanitized, allergen-free, safe temperature, ready, occupied, contaminated, and closed.", + "Community governance": "Maintain a public glossary for authority, adult, citizen, harm, consent, quorum, majority, conflict, and appeal, with revision history." + } + }, + { + "unit_id": "rights-and-definitions-of-the-way.article-eight", + "public_title": "Article Eight — Rights with living limits", + "ad_absurdum": { + "overextension": "If ‘harm none’ means zero possible risk, movement, medicine, construction, agriculture, transport, speech, and ordinary life become impermissible.", + "counter_overextension": "If consent alone makes any action right, coercion, misinformation, dependency, externalized harm, and irreversible effects disappear behind a checkbox.", + "boundary": "Define relevant harms, affected parties, probabilities, reversibility, alternatives, ecological effects, comprehension, voluntariness, and withdrawal; protect diminished autonomy without erasing agency." + }, + "worst_practices": [ + "Use harm as an undefined accusation or require certainty before acknowledging foreseeable risk.", + "Treat a signature, click, silence, payment, dependency, or prior behavior as sufficient informed consent.", + "Invoke nature to excuse preventable suffering or ignore human-caused externalities.", + "Count only direct immediate harm to consenting parties while exporting costs to others or the future." + ], + "best_practices": [ + "Specify who may be harmed, how, with what likelihood, duration, reversibility, and evidence.", + "Separate information, comprehension, voluntariness, capacity, permission, and continuing assent.", + "Use least-harm alternatives, monitoring, stop conditions, remedy, and withdrawal.", + "Include indirect, cumulative, ecological, and distributional effects in the rights analysis." + ], + "applications": { + "Medical": "Use informed consent, capacity support, surrogate protection, risk-benefit review, alternatives, continuing assent, and withdrawal.", + "Construction": "Balance property, schedule, worker safety, public exposure, environmental effects, and stop-work rights through documented risk controls.", + "Engineering": "Build safety, privacy, security, accessibility, environmental, misuse, and rollback analysis into requirements and verification.", + "Agriculture": "Assess worker, animal, soil, water, biodiversity, consumer, neighbor, and future-season effects alongside owner consent and yield.", + "Jurisprudence": "Define protected interests, coercion, necessity, proportionality, informed waiver, standing, remedy, and the rights of affected nonparties.", + "Transportation and distribution": "Balance mobility and commerce against worker fatigue, public safety, emissions, access, dangerous goods, and community burden.", + "Child craft": "Use age-appropriate information, assent, protective limits, privacy, bodily autonomy, and periodic reevaluation as capacity grows.", + "Information systems": "Use specific, revocable, comprehensible consent plus data minimization, purpose limits, security, accessibility, and protection from dark patterns.", + "Emergency response": "Use necessity and proportionality, document rights restrictions, preserve humane treatment, and terminate extraordinary measures promptly.", + "Hospitality and sanitation": "Protect bodily safety, privacy, accessibility, food safety, worker rights, and environmental health while preserving reasonable guest choice.", + "Community governance": "Require public harm definitions, affected-party voice, minority protections, reversible pilots where possible, and remedies for imposed costs." + } + } +] diff --git a/src/_data/research/claims.yml b/src/_data/research/claims.yml index 2167adc..82ef6d6 100644 --- a/src/_data/research/claims.yml +++ b/src/_data/research/claims.yml @@ -1,5 +1,14 @@ +- id: article-one-food-insecurity-health + article: rights-and-definitions-of-the-way.article-one + stance: support + status: defended-component + claim: "Food insecurity is associated with adverse health outcomes, and reducing food insecurity is a material health intervention rather than merely charitable preference." + source_ids: + - gundersen-ziliak-2015-food-insecurity + limitation: "The review supports a survival floor but does not determine contribution rules, exclusions, or allocation under acute scarcity." + - id: article-two-autonomy-and-duty - article: rights.article-two + article: rights-and-definitions-of-the-way.article-two stance: support status: defended-component claim: "Necessary health or survival work is more likely to be sustained when people experience volition, competence, and supportive connection rather than pressure or coercion." @@ -8,7 +17,7 @@ limitation: "This supports the page's autonomy-preserving interpretation, not every duty named in the canon." - id: article-two-sanitation-is-health-work - article: rights.article-two + article: rights-and-definitions-of-the-way.article-two stance: support status: evidence-informed claim: "Safe sanitation is material health infrastructure rather than merely an aesthetic preference." @@ -17,7 +26,7 @@ limitation: "The guideline does not settle who owes the work or how responsibility should be distributed." - id: article-two-will-under-scarcity - article: rights.article-two + article: rights-and-definitions-of-the-way.article-two stance: dissent status: defended-risk claim: "Poverty and scarcity can consume cognitive resources, so compliance, refusal, or poor performance cannot automatically be treated as evidence of free will or character." @@ -26,10 +35,92 @@ limitation: "The study does not measure consent directly; the application to voluntariness is a bounded inference." - id: article-two-trauma-evidence-limit - article: rights.article-two + article: rights-and-definitions-of-the-way.article-two stance: limit status: evidence-open claim: "Trauma-informed care is widely implemented, but comparative evidence remains insufficient to determine effects across patient and client outcomes." source_ids: - ahrq-2025-trauma-informed-care limitation: "The page may defend attention to trauma while keeping intervention effectiveness explicitly unresolved." + +- id: article-three-reciprocity-escalation + article: rights-and-definitions-of-the-way.article-three + stance: dissent + status: defended-risk + claim: "Automatic tit-for-tat responses can turn low-intensity incivility into reciprocal escalation and increasingly aggressive conduct." + source_ids: + - andersson-pearson-1999-incivility + limitation: "The article is theoretical and workplace-focused; it warns against automatic reciprocity but does not model every conflict." + +- id: article-three-structured-communication + article: rights-and-definitions-of-the-way.article-three + stance: support + status: evidence-informed + claim: "High-consequence communication can be made safer through shared tools for explicit messages, team leadership, situation monitoring, mutual support, and patient involvement." + source_ids: + - ahrq-2023-teamstepps + limitation: "TeamSTEPPS is a healthcare implementation framework; transfer to other domains requires adaptation and evaluation." + +- id: article-four-procedural-justice-association + article: rights-and-definitions-of-the-way.article-four + stance: mixed + status: defended-association + claim: "Perceived procedural justice is consistently associated with perceived legitimacy, and legitimacy is usually associated with legal compliance." + source_ids: + - nagin-telep-2017-procedural-justice + limitation: "The review found that a causal chain from changed institutional practice to changed compliance had not been established." + +- id: article-five-contextual-functioning + article: rights-and-definitions-of-the-way.article-five + stance: limit + status: framework-backed + claim: "Functioning and disability should be described in context, including environmental supports and barriers, rather than treated as a fixed global property of the person." + source_ids: + - who-2001-icf + limitation: "The ICF is descriptive and health-related; it does not define political adulthood or authorize removal of civil status." + +- id: article-five-field-specific-competence + article: rights-and-definitions-of-the-way.article-five + stance: support + status: framework-backed + claim: "Competency can be defined by role-relevant outcomes and connected to curricula, practice activities, and assessment rather than inferred from title alone." + source_ids: + - who-2022-uhc-competency + limitation: "The framework concerns health-worker education and cannot be generalized into a universal civic competence test without new validation." + +- id: article-six-bounded-incident-authority + article: rights-and-definitions-of-the-way.article-six + stance: support + status: operational-framework + claim: "Emergency authority can be structured through common terminology, explicit command and coordination, resource management, transfer, and demobilization." + source_ids: + - fema-2017-nims + limitation: "Incident management doctrine supports bounded emergency coordination, not permanent or general political authority." + +- id: article-seven-normative-language + article: rights-and-definitions-of-the-way.article-seven + stance: support + status: standard-backed + claim: "Controlled definitions for requirement words can reduce ambiguity and make obligations and exceptions more interoperable." + source_ids: + - ietf-1997-rfc2119 + - ietf-2017-rfc8174 + limitation: "BCP 14 applies to technical documents that invoke it; ordinary, moral, and legal language requires additional contextual definition." + +- id: article-eight-informed-consent-elements + article: rights-and-definitions-of-the-way.article-eight + stance: support + status: doctrine-backed + claim: "Valid informed consent requires information, comprehension, and voluntariness rather than a signature or nominal permission alone." + source_ids: + - hhs-1979-belmont-report + limitation: "The Belmont Report governs human-subject research; extending its consent model to other domains is an argued analogy, not direct jurisdiction." + +- id: article-eight-vulnerability-and-risk + article: rights-and-definitions-of-the-way.article-eight + stance: limit + status: doctrine-backed + claim: "Respect for persons includes both autonomy and protection for diminished autonomy, while beneficence requires explicit assessment of risks, benefits, alternatives, and vulnerable populations." + source_ids: + - hhs-1979-belmont-report + limitation: "Protection must not be converted into total erasure of agency, and the report does not resolve every conflict among autonomy, harm, and public duty." diff --git a/src/_data/research/sources.yml b/src/_data/research/sources.yml index af5cb56..1486668 100644 --- a/src/_data/research/sources.yml +++ b/src/_data/research/sources.yml @@ -45,3 +45,119 @@ reviewed_on: "2026-07-21" relevance: "Assesses trauma-informed care models and patient or client outcomes across healthcare and social-service settings." boundary: "Evidence was insufficient for clear outcome determinations; trauma-informed language must not be presented as evidence-closed." + +- id: gundersen-ziliak-2015-food-insecurity + title: "Food insecurity and health outcomes" + authors: "Craig Gundersen; James P. Ziliak" + year: 2015 + publication: "Health Affairs 34(11):1830-1839" + type: peer-reviewed review + doi: "10.1377/hlthaff.2015.0645" + url: "https://doi.org/10.1377/hlthaff.2015.0645" + reviewed_on: "2026-07-21" + relevance: "Reviews evidence linking food insecurity with adverse health outcomes and describes nutrition assistance as an important means of reducing food insecurity." + boundary: "Supports a material survival floor; it does not determine contribution rules, sanctions, or allocation under acute scarcity." + +- id: andersson-pearson-1999-incivility + title: "Tit for Tat? The Spiraling Effect of Incivility in the Workplace" + authors: "Lynne M. Andersson; Christine M. Pearson" + year: 1999 + publication: "Academy of Management Review 24(3):452-471" + type: peer-reviewed theoretical article + doi: "10.5465/AMR.1999.2202131" + url: "https://doi.org/10.5465/AMR.1999.2202131" + reviewed_on: "2026-07-21" + relevance: "Models how low-intensity incivility can pass tipping points and spiral into increasingly aggressive reciprocal behavior." + boundary: "Supports treating automatic reciprocity as an escalation risk; it does not establish that every conflict follows the proposed spiral." + +- id: ahrq-2023-teamstepps + title: "TeamSTEPPS 3.0" + authors: "Agency for Healthcare Research and Quality" + year: 2023 + publication: "AHRQ evidence-based teamwork and patient-safety curriculum" + type: evidence-based implementation framework + url: "https://www.ahrq.gov/teamstepps-program/index.html" + reviewed_on: "2026-07-21" + relevance: "Organizes communication, team leadership, situation monitoring, mutual support, and active patient involvement into trainable tools." + boundary: "Supports structured high-consequence communication in healthcare; transfer to other domains requires contextual validation." + +- id: nagin-telep-2017-procedural-justice + title: "Procedural Justice and Legal Compliance" + authors: "Daniel S. Nagin; Cody W. Telep" + year: 2017 + publication: "Annual Review of Law and Social Science 13:5-28" + type: peer-reviewed review + doi: "10.1146/annurev-lawsocsci-110316-113310" + url: "https://doi.org/10.1146/annurev-lawsocsci-110316-113310" + reviewed_on: "2026-07-21" + relevance: "Finds consistent associations among perceived procedural justice, legitimacy, and compliance in perception-based studies." + boundary: "The review explicitly states that a causal chain from changed institutional practice to changed compliance had not been established." + +- id: who-2001-icf + title: "International Classification of Functioning, Disability and Health" + authors: "World Health Organization" + year: 2001 + publication: "WHO international classification and framework" + type: international standard framework + url: "https://www.who.int/standards/classifications/international-classification-of-functioning-disability-and-health" + reviewed_on: "2026-07-21" + relevance: "Treats functioning and disability as contextual, including environmental factors rather than locating capacity only inside the person." + boundary: "Provides a framework for describing functioning; it does not define civic adulthood or authorize removal of legal status." + +- id: who-2022-uhc-competency + title: "Global Competency and Outcomes Framework for Universal Health Coverage" + authors: "World Health Organization" + year: 2022 + publication: "World Health Organization technical document" + type: competency framework + isbn: "978-92-4-003466-2" + url: "https://www.who.int/publications/i/item/9789240034662" + reviewed_on: "2026-07-21" + relevance: "Defines role-relevant competency domains and connects outcomes with curricula, learning activities, and assessment approaches." + boundary: "Supports field-specific demonstrated competence; it applies to health-worker education, not universal political standing." + +- id: fema-2017-nims + title: "National Incident Management System, Third Edition" + authors: "Federal Emergency Management Agency" + year: 2017 + publication: "FEMA incident-management doctrine" + type: official operational framework + url: "https://training.fema.gov/is/coursematerials.aspx?code=IS-700.b" + reviewed_on: "2026-07-21" + relevance: "Defines common terminology, command and coordination structures, resource management, transfer, and demobilization for incidents." + boundary: "Supports bounded emergency authority and interoperable command; incident doctrine is not a general constitution for ordinary governance." + +- id: ietf-1997-rfc2119 + title: "RFC 2119: Key words for use in RFCs to Indicate Requirement Levels" + authors: "Scott Bradner" + year: 1997 + publication: "Internet Engineering Task Force Best Current Practice 14" + type: technical standard + doi: "10.17487/RFC2119" + url: "https://www.rfc-editor.org/info/rfc2119/" + reviewed_on: "2026-07-21" + relevance: "Defines consistent meanings for MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY in technical specifications." + boundary: "Demonstrates the value of controlled normative language; it does not settle moral, legal, or ordinary-language definitions." + +- id: ietf-2017-rfc8174 + title: "RFC 8174: Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words" + authors: "Barry Leiba" + year: 2017 + publication: "Internet Engineering Task Force Best Current Practice 14" + type: technical standard clarification + doi: "10.17487/RFC8174" + url: "https://www.rfc-editor.org/info/rfc8174/" + reviewed_on: "2026-07-21" + relevance: "Clarifies when standardized requirement words carry their defined force and reduces ambiguity caused by inconsistent capitalization." + boundary: "The clarification is limited to documents invoking BCP 14 and should not be projected onto all speech." + +- id: hhs-1979-belmont-report + title: "The Belmont Report: Ethical Principles and Guidelines for the Protection of Human Subjects of Research" + authors: "National Commission for the Protection of Human Subjects of Biomedical and Behavioral Research" + year: 1979 + publication: "United States Department of Health and Human Services" + type: foundational ethics report + url: "https://www.hhs.gov/ohrp/regulations-and-policy/belmont-report/read-the-belmont-report/index.html" + reviewed_on: "2026-07-21" + relevance: "Connects respect for persons with information, comprehension, and voluntariness; also requires risk-benefit assessment and protection for diminished autonomy." + boundary: "Governs human-subject research ethics and supplies a strong consent model; not every civil or private interaction is research." diff --git a/src/_data/research_data.js b/src/_data/research_data.js new file mode 100644 index 0000000..4ea40fd --- /dev/null +++ b/src/_data/research_data.js @@ -0,0 +1,50 @@ +import { readFile } from 'node:fs/promises'; +import yaml from 'js-yaml'; + +// === MODULE_BUILD === +// 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. +// owner: Erin Spencer +// public_surface: research_data.sources, research_data.claims +// internal_surface: readYamlList +// auth_boundary: none +// storage_boundary: read +// 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 +// === 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. + +// === BOUNDARIES === +// id: article_lab_research_data_storage_boundary +// summary: Reads two repository-owned YAML ledgers during static-site generation and returns parsed arrays. +// auth_boundary: none +// storage_boundary: read +// network_boundary: none +// user_data_boundary: none +// admin_only: false +// pii: none +// secrets: none +// side_effects: none +// owner: Erin Spencer +// === END BOUNDARIES === + +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; +} + +export default async function researchData() { + const [sources, claims] = await Promise.all([ + readYamlList('src/_data/research/sources.yml'), + readYamlList('src/_data/research/claims.yml') + ]); + return { sources, claims }; +} diff --git a/src/lab/index.njk b/src/lab/index.njk index 71684b0..9ac3f5e 100644 --- a/src/lab/index.njk +++ b/src/lab/index.njk @@ -1,8 +1,32 @@ --- layout: layouts/base.njk title: Article Lab -description: A structured conversation between canonical body text, notes, research, dissent, and unresolved evidence gaps. +description: A structured conversation between canonical body text, notes, research, absurd-limit tests, practice failures, practice strengths, and domain applications. --- -

Interpretation with visible seams

Article Lab

The Lab treats the body text and its annotations as speakers in a deliberate conversation. It records what the tension may prevent, what research supports or challenges the claim, and where evidence is still absent. It does not rewrite the canon or claim edcmbone measurement status.

-
{% for unit in generated.canon.units %}Lab

{{ unit.title }}

{{ unit.notes.length }} separately parsed note{% if unit.notes.length != 1 %}s{% endif %} · source lines {{ unit.startLine }}–{{ unit.endLine }}

{% endfor %}
-

Research coverage

The Lab route exists for every discovered canonical unit. Reviewed support, dissent, mixed evidence, and synthesis are intentionally published unit by unit rather than mass-invented.

+
+

Interpretation with visible seams

+

Article Lab

+

Each Rights article is tested from several directions: the body text and notes remain distinct speakers; reductio ad absurdum exposes destructive overextensions; worst and best practices translate the tension into operations; domain applications test whether the reading survives contact with different kinds of work; reviewed research remains visibly bounded.

+
+
+

Rights Article laboratories

+
+ {% for record in article_lab %} + {% for unit in generated.canon.units %} + {% if unit.id == record.unit_id %} + {% set claims = research_data.claims | where("article", unit.id) %} + + Lab +

{{ record.public_title }}

+

{{ unit.notes.length }} separately parsed note{% if unit.notes.length != 1 %}s{% endif %} · {{ claims.length }} reviewed claim{% if claims.length != 1 %}s{% endif %} · {{ record.applications | length }} application domains

+
+ {% endif %} + {% endfor %} + {% endfor %} +
+
+
+

Method boundary

+

Applications are operational hypotheses, not claims that one rule transfers unchanged across domains. Research sources support, dissent from, or limit a particular component; they do not prove an Article as a whole. Other canonical units retain generated Lab routes, but this index begins with the eight Rights articles as the first complete comparative set.

+
+

Research coverage

The initial pack establishes reviewed contact for all eight Rights articles. It is not exhaustive: each claim remains open to stronger replication, domain-specific evidence, direct dissent, and evidence from outside United States and institutional settings.

diff --git a/src/lab/unit.njk b/src/lab/unit.njk index 955d635..539a07b 100644 --- a/src/lab/unit.njk +++ b/src/lab/unit.njk @@ -7,9 +7,79 @@ pagination: permalink: "/lab/{{ unit.routeSlug }}/" title: "Lab: {{ unit.title }}" --- +{% set labMatches = article_lab | where("unit_id", unit.id) %} +{% set lab = labMatches[0] %} +{% set claims = research_data.claims | where("article", unit.id) %} -

Interpretive laboratory

{{ unit.title }}

The body text and its notes are treated as distinct speakers. This is a review surface, not a substitute canon and not an edcmbone metric runtime.

-

Conversation

Speaker A · main text

The exact canonical unit is one interaction away so this interpretive layer cannot quietly replace it.

Open exact source and provenance

{% if unit.notes.length %}{% for note in unit.notes %}
Speaker B · note {{ note.marker }}

{{ note.text }}

{% endfor %}{% else %}

No separately parsed note text

This unit may contain no numbered annotations, or its tension may be structural rather than footnoted.

{% endif %}
-

What the tension prevents

A reviewed synthesis has not yet been admitted. The Lab records the gap rather than inventing a clean reconciliation.

-

Research field

Support

Reviewed support

hmmm — no reviewed source is attached to this unit yet.

Dissent

Reviewed dissent

hmmm — no reviewed dissenting source is attached yet.

Mixed

Context and limits

hmmm — context classification awaits editorial review.

+
+

Interpretive laboratory

+

{% if lab %}{{ lab.public_title }}{% else %}{{ unit.title }}{% endif %}

+

The body text, notes, research, failure tests, and applications remain separate layers. This is a review surface, not substitute canon and not an edcmbone metric runtime.

+
+
+

Conversation

+
Speaker A · main text

The exact canonical unit is one interaction away so this interpretive layer cannot quietly replace it.

Open exact source and provenance

+ {% if unit.notes.length %} + {% for note in unit.notes %}
Speaker B · note {{ note.marker }}

{{ note.text }}

{% endfor %} + {% else %} +

No separately parsed note text

This unit may contain no numbered annotations, or its tension may be structural rather than footnoted.

+ {% endif %} +
+{% if lab %} +
+

Limit testing

+

Reductio ad absurdum

+
+
Overextension

Read without its counterweight

{{ lab.ad_absurdum.overextension }}

+
Inverse collapse

Reject the Article absolutely

{{ lab.ad_absurdum.counter_overextension }}

+
Working boundary

What survives both failures

{{ lab.ad_absurdum.boundary }}

+
+
+
+

Operational contrast

+

Worst practices and best practices

+
+
Worst practices

How the Article becomes harmful

    {% for practice in lab.worst_practices %}
  • {{ practice }}
  • {% endfor %}
+
Best practices

How the tension becomes usable

    {% for practice in lab.best_practices %}
  • {{ practice }}
  • {% endfor %}
+
+
+
+

Contact across kinds of work

+

Applications by domain

+

These are bounded application hypotheses. A domain must preserve its own standards, evidence, lawful duties, and safety constraints rather than importing the Article as a slogan.

+
+ {% for domain, application in lab.applications %}
{{ domain }}

{{ application }}

{% endfor %} +
+
+
+

Reviewed contact

+

Research field

+ {% if claims.length %} +
+ {% for claim in claims %} + {% set stanceClass = "status-research" %} + {% if claim.stance == "dissent" %}{% set stanceClass = "status-risk" %}{% endif %} + {% if claim.stance == "limit" or claim.stance == "mixed" %}{% set stanceClass = "status-frontier" %}{% endif %} +
+ {{ claim.stance }} · {{ claim.status }} +

{{ claim.claim }}

+

Evidence boundary: {{ claim.limitation }}

+
Sources:
    + {% for sourceId in claim.source_ids %} + {% for source in research_data.sources %} + {% if source.id == sourceId %}
  • {{ source.title }}
    {{ source.type }} · reviewed {{ source.reviewed_on }}
  • {% endif %} + {% endfor %} + {% endfor %} +
+
+ {% endfor %} +
+ {% else %} +

No reviewed claim is attached to this unit yet.

+ {% endif %} +
+{% else %} +

What the tension prevents

A reviewed synthesis, absurd-limit test, practice contrast, and domain application set have not yet been admitted for this non-Rights unit.

+

Research field

No reviewed source is attached to this unit yet.

+{% endif %}
Open EDCM-style heuristic boundary

This page may later expose transparent text-comparison heuristics such as constraint mismatch, drift, dissonance, divergence, and turn balance. Those readings must remain labeled illustrative and may not claim edcmbone runtime status.

diff --git a/tests/accessibility.spec.mjs b/tests/accessibility.spec.mjs index 4696231..1749dd0 100644 --- a/tests/accessibility.spec.mjs +++ b/tests/accessibility.spec.mjs @@ -1,12 +1,17 @@ // Usage: run `npm run test:a11y` after `npm run build`; serious and critical axe findings fail. // Evidence boundary: automated axe checks do not replace manual keyboard, screen-reader, or cognitive-access review. +import { readFileSync } from 'node:fs'; import { createRequire } from 'node:module'; import { test, expect } from '@playwright/test'; const require = createRequire(import.meta.url); const axePath = require.resolve('axe-core/axe.min.js'); +const canon = JSON.parse(readFileSync('src/_data/generated/canon.json', 'utf8')); +const articleLab = JSON.parse(readFileSync('src/_data/article_lab.json', 'utf8')); +const firstLabUnit = canon.units.find(unit => unit.id === articleLab[0].unit_id); +if (!firstLabUnit) throw new Error(`missing Lab canon unit ${articleLab[0].unit_id}`); -for (const route of ['/', '/preamble/', '/articles/', '/articles/article-two/', '/way/', '/projects/']) { +for (const route of ['/', '/preamble/', '/articles/', '/articles/article-two/', '/way/', '/lab/', `/lab/${firstLabUnit.routeSlug}/`, '/projects/']) { test(`${route} has no serious or critical automated accessibility violations`, async ({ page }) => { await page.goto(route); await page.addScriptTag({ path: axePath }); diff --git a/tests/generated-site.test.mjs b/tests/generated-site.test.mjs index 43f9d87..ec7f129 100644 --- a/tests/generated-site.test.mjs +++ b/tests/generated-site.test.mjs @@ -57,6 +57,29 @@ test('generated deployment artifact contains all rights article vertical slices' } }); +test('every Rights Article Lab renders absurd-limit, practice, domain, and research sections', async () => { + const canon = JSON.parse(await readFile('src/_data/generated/canon.json', 'utf8')); + const articleLab = JSON.parse(await readFile('src/_data/article_lab.json', 'utf8')); + const requiredDomains = [ + 'Medical', 'Construction', 'Engineering', 'Agriculture', 'Jurisprudence', + 'Transportation and distribution', 'Child craft', 'Information systems', + 'Emergency response', 'Hospitality and sanitation', 'Community governance' + ]; + + for (const record of articleLab) { + const unit = canon.units.find(candidate => candidate.id === record.unit_id); + assert.ok(unit, `missing canon unit ${record.unit_id}`); + const html = await readFile(`_site/lab/${unit.routeSlug}/index.html`, 'utf8'); + assert.match(html, /Reductio ad absurdum/); + assert.match(html, /Worst practices and best practices/); + assert.match(html, /Applications by domain/); + assert.match(html, /Research field/); + assert.match(html, /Evidence boundary/); + assert.match(html, /href="https?:\/\//); + for (const domain of requiredDomains) assert.match(html, new RegExp(domain.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))); + } +}); + test('generated deployment artifact publishes verifiable build identity', async () => { const build = JSON.parse(await readFile('_site/build.json', 'utf8')); assert.equal(build.repository, 'The-Interdependency/The-Interdependency.github.io'); diff --git a/tests/research-ledger.test.mjs b/tests/research-ledger.test.mjs index 3b2aa72..6f82b38 100644 --- a/tests/research-ledger.test.mjs +++ b/tests/research-ledger.test.mjs @@ -1,27 +1,55 @@ -// Usage: run through `npm test`; add claims only with source ids, limitations, and reviewed metadata. -// Evidence boundary: validates provenance structure, not the truth of every source claim. +// Usage: run through `npm test`; add claims only with source ids, limitations, reviewed metadata, and a bounded Article Lab record. +// Evidence boundary: validates provenance 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 requiredDomains = [ + 'Medical', + 'Construction', + 'Engineering', + 'Agriculture', + 'Jurisprudence', + 'Transportation and distribution', + 'Child craft', + 'Information systems', + 'Emergency response', + 'Hospitality and sanitation', + 'Community governance' +]; + 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); + 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(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); } for (const claim of claims) { assert.ok(['support', 'dissent', 'limit', 'mixed'].includes(claim.stance)); + 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) { + assert.ok(record.public_title); + assert.ok(record.ad_absurdum?.overextension && record.ad_absurdum?.counter_overextension && record.ad_absurdum?.boundary); + assert.ok(Array.isArray(record.worst_practices) && record.worst_practices.length >= 4); + 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`); + assert.ok(claims.some(claim => claim.article === record.unit_id), `${record.unit_id} needs reviewed research contact`); + } }); diff --git a/tests/site.spec.mjs b/tests/site.spec.mjs index e64684e..3e6b7cc 100644 --- a/tests/site.spec.mjs +++ b/tests/site.spec.mjs @@ -1,14 +1,23 @@ // Usage: run `npm run test:e2e` after `npm run build`; Playwright starts the loopback static server. // Evidence boundary: checks route reachability and visible content, not external DNS or Pages freshness. +import { readFileSync } from 'node:fs'; import { test, expect } from '@playwright/test'; +const canon = JSON.parse(readFileSync('src/_data/generated/canon.json', 'utf8')); +const articleLab = JSON.parse(readFileSync('src/_data/article_lab.json', 'utf8')); +const labRoutes = articleLab.map(record => { + const unit = canon.units.find(candidate => candidate.id === record.unit_id); + if (!unit) throw new Error(`missing Lab canon unit ${record.unit_id}`); + return { ...record, route: `/lab/${unit.routeSlug}/` }; +}); + const routes = [ ['/', /A way through complexity/], ['/preamble/', /Humanity faces extinction/], ['/articles/', /Publication drafts/], ['/articles/article-two/', /Freedom without abandonment/], ['/way/', /The Way/], - ['/lab/', /Article Lab/], + ['/lab/', /Rights Article laboratories/], ['/source/', /Source/], ['/projects/', /Projects/], ['/artifacts/', /Artifacts/], @@ -42,3 +51,15 @@ test('all eight rights articles are reachable from the article index', async ({ await expect(link).toBeVisible(); } }); + +test('all eight Rights Article Labs are indexed and expose the shared contact structure', async ({ page }) => { + await page.goto('/lab/'); + for (const record of labRoutes) await expect(page.locator(`a[href="${record.route}"]`)).toBeVisible(); + + await page.goto(labRoutes[0].route); + await expect(page.locator('body')).toContainText('Reductio ad absurdum'); + await expect(page.locator('body')).toContainText('Worst practices and best practices'); + await expect(page.locator('body')).toContainText('Applications by domain'); + await expect(page.locator('body')).toContainText('Child craft'); + await expect(page.locator('body')).toContainText('Research field'); +});