# =============================================================================
# Resourcehip — Methodology: Single Source of Truth
# =============================================================================
# Version:   1.5
# Licence:   Methodology content — CC BY-NC 4.0
#            Pipeline code and prompt templates — Resourcehip Ltd (proprietary)
#
# PURPOSE
# This file is the single source of truth for all scoring logic.
# It drives three things simultaneously:
#   1. The LLM prompts sent by rate.py (via the scoring_rubric and llm_instructions fields)
#   2. The HIP Score calculation (weights, RI normalisation, thresholds)
#   3. The human-readable Scoring Methodology document (regenerated from this file)
#
# Editing this file changes all three. Never edit the Word doc directly
# to change scoring criteria — edit here, then regenerate.
#
# PIPELINE FLOW (brief)
#   rate.py reads submitted product data (JSON)
#   → loops through dimensions one at a time
#   → builds a focused prompt from this file
#   → sends to the scoring model
#   → validates JSON response against output_schema
#   → calculates weighted HIP Score
#   → renders Markdown rating page via Jinja2 template
#   → publishes the rating page
# =============================================================================


# -----------------------------------------------------------------------------
# METADATA
# -----------------------------------------------------------------------------
metadata:
  version: "1.5"
  effective_date: "2026-07"
  licence_methodology: "CC BY-NC 4.0"
  licence_code: "Proprietary — Resourcehip Ltd"
  contact: "methodology@resourcehip.com"
  changelog:
    - version: "1.5"
      date: "2026-07-13"
      notes: >
        Governance-only bump (RES-1621, children B+C+F of RES-1378 versioning &
        ISO audit-trail design). NO scoring rule, weight, rubric, or dimension
        changes; HIP scores do not move. Three additions, all under governance:
        (1) rating_lifecycle — a two-tier review policy. validity_period_years: 2
        (full re-score due; tallies with the 24-month HIP Mark licence in
        pricing.md/rating-terms.md §7.3) and interim_review_period_years: 1
        (annual interim review = trigger check + evidence sweep, NOT a forced
        full re-score; keeps score.py's +1yr next_review truthful and the
        "reviewed annually" licensee claim defensible). next_review is the
        interim date (+1y); re_rating_due is the full re-score date (+2y).
        expiry_grace_days: 30; rerating_triggers now include model_version_change
        (a scoring-model swap/upgrade is a declared re-rating trigger alongside a
        methodology bump — the model has a training-data cutoff that ages against
        moving source data). (2) audit_log.movement_fields += source_snapshot_id,
        scoring_model, rating_version_id (full provenance triple per audit-log
        entry for ISO reconstruction). (3) republish_notifications — notification
        channels/SLAs, including a >=30-day mark-holder notice before a
        mark-withdrawing score drop. Implementation: score.py next_review/
        re_rating_due now read the lifecycle config instead of a hardcoded +1;
        audit_log.log_score_movement persists the provenance triple. Design:
        HIP_VERSIONING_ISO_DESIGN.md §3.2/§3.3/§3.6/§4. CEO sign-off: RES-1621.
    - version: "1.4"
      date: "2026-07-01"
      notes: >
        Data update (no methodology version bump): refreshed the R-dimension
        legal source reference from the stale amending reg (EU) 2021/341 to the
        current EU regime — Right to Repair Directive (EU) 2024/1799 (applies
        31 Jul 2026) plus ESPR (EU) 2024/1781 (supersedes Ecodesign Directive
        2009/125/EC). Updated the ecodesign_in_scope field description to anchor
        on R2R Directive Annex II / in-force ESPR product-specific acts.
        Documentation only — NO scoring or boolean changes; all eight
        category_baselines remain ecodesign_in_scope: false (none are in R2R
        Annex II and no relevant ESPR delegated act is yet in force). Sources
        verified via EUR-Lex 2026-07-01. CEO sign-off: RES-1437 (2026-07-01).
    - version: "1.4"
      date: "2026-07"
      notes: >
        Added category_weight_profiles: seven product-type profiles
        (buy_it_for_life_durables, consumables_razor_blade, consumable_unit,
        safety_sealed, software_dependent_electronics, battery_bearing_electronics,
        single_use_packaging). Added category_type_mapping for deterministic
        product_type → profile lookup. Added na_renormalisation_rules with
        deterministic weight redistribution. Added system_boundary_rules for
        consumable-dependent products. Added gating_factors for software EOL,
        safety-sealed sealing, and non-replaceable batteries. Added
        composition_schema with declared-battery-chemistry as LLM prompt-anchor
        guidance (no post-score adjustment) and per-category published-default
        fallbacks. Input migration: new fields safety_sealed, battery_replaceable,
        battery_chemistry, has_consumable_stream, consumable_category,
        is_software_dependent all default-false/null so v1.3 inputs continue
        to score under v1.4 base weights without modification.
        CEO sign-off: RES-1206 (2026-07). Board approval: 7a1f78e1.
    - version: "1.4"
      date: "2026-07"
      notes: >
        Added governance block: review_policy (review-by-exception with
        random-sample audits), republish_thresholds, subcategory_rule,
        slug_policy, and audit_log schema. Supersedes the Hybrid/tier-1
        model from the original RES-1208 spec per CEO revision (2026-06-11).
        CEO sign-off: RES-1208 / RES-1209.
    - version: "1.4"
      date: "2026-06-14"
      notes: >
        PHASE 1 SCOPE DECISION (RES-1207, CEO approved 2026-06-14): single-use
        packaging is rated and scored when submitted (category_weight_profiles
        single_use_packaging profile now complete), but packaging ratings are
        NOT published as standalone searchable products on resourcehip.com.
        Instead, packaging RC and RI scores are visible embedded in parent
        product ratings. This approach maintains focus on primary consumer
        products during soft launch. Packaging-as-primary-products deferred
        to Phase 2 expansion (subject to demand validation and business model
        confirmation). See RES-1207 issue for full decision log.
    - version: "1.3"
      date: "2026-04-28"
      notes: >
        RI Rule 2.5 added: bio-based renewable materials (plant fibres, wood,
        natural rubber, cork, bamboo) are guaranteed a minimum Extractive band
        (-5 to -1) — the Depleting floor does not apply. Rule 3 updated to
        explicitly exclude bio-based products. Certification (FSC, GOTS, GOLS,
        ROC, Rainforest Alliance) still enables Rule 4/5 uplift to Renewable or
        above. CEO sign-off: RES-104 (2026-04-28).
    - version: "1.3"
      date: "2026-04-27"
      notes: >
        Data update (no methodology version bump): added category_baselines for
        6 bio-based product categories — cork_products, bamboo_kitchenware,
        linen_hemp_accessories, wooden_toys_games, natural_latex_sleep,
        solid_personal_care_bars. solid_personal_care_bars is flagged
        PHASE_5_SCOPE_CHECK_REQUIRED pending Phase 5 scope confirmation for
        consumable products. CEO sign-off: RES-57 (2026-04-27).
    - version: "1.3"
      date: "2026-04"
      notes: >
        Updated RI.llm_instructions with explicit scoring rules and worked examples
        to prevent pattern-matching drift. Added mandatory rubric citation requirement
        and clarified Depleting vs Extractive band criteria.
    - version: "1.1"
      date: "2026-03"
      notes: >
        Added Regenerative Index (RI) as seventh dimension. Adjusted weights:
        MSI 20%, SCR 18%, RC 18%, R 13%, SEI 8%, PL 8%, RI 15%.
        RI runs -10 to +10 (unique — no other mainstream rating has negative floor).
    - version: "1.0"
      date: "2026-02"
      notes: "Initial six-dimension framework."
  standards_alignment:
    iso_14024_2026:
      status: "informed"
      claim: >
        HIP is ISO 14024-informed, not ISO-certified. Resourcehip is building
        toward certification: Phase 2 (Q4 2026–2028) adds independent peer
        review, a Criteria Board, and third-party audit.
      aligned_pillars:
        - "Transparency: methodology published under CC BY-NC 4.0; all scoring rubrics and data sources are public"
        - "Multi-criteria: seven dimensions covering material scarcity, supply chain, circularity, repairability, social impact, longevity, and regenerative potential"
        - "Science-basis: rubrics cite peer-reviewed sources (OECD, ILO, RBA, USGS, BEUC)"
      deferred_to_phase_2:
        - "Independence: HIP is currently founder-led; ISO 14024 requires an independent multi-stakeholder governance board"
        - "Third-party audit: HUMAN_REVIEW_CHECKLIST is an internal verification gate; ISO requires external auditor sign-off"
        - "Periodic reassessment cycle: ISO requires formal 3–5 year review; HIP updates are currently reactive"
      notes: >
        Non-LCA dimensions (RC, R, RI) are design-criteria that inform LCA
        outcomes, not LCA-derived scores under ISO 14040/44. The Regenerative
        Index is a proprietary Resourcehip extension with no ISO 14024
        equivalent. Phase 2 roadmap: peer review Q4 2026, Criteria Board Q1
        2027, third-party audit Q2–Q3 2027, formal certification pathway
        2027–2028. CEO sign-off: RES-544 (2026-05-12).
    audit_trail_mapping_doc:
      path: "pipeline/HIP_VERSIONING_ISO_DESIGN.md#5"
      title: "ISO 14024 / 14025 clause mapping (normative)"
      description: >
        §5 is the normative verification matrix binding each ISO clause to a
        concrete Resourcehip mechanism. Covers ISO 14024:2018 (Type I), with
        cross-checks against ISO 14025:2006 (Type III, non-conforming by
        design) and ISO 14021:2016 (Type II, self-declared claims). Each row
        carries a Built / Gap / Phase 2 status. This is the audit-trail
        provenance reference for the standards claims above.
      design_source: "RES-1378 design §3.4, §6.D"
      published_by: "RES-1623"


# -----------------------------------------------------------------------------
# HIP SCORE CALCULATION
# -----------------------------------------------------------------------------
hip_score:
  # HIP Score = weighted sum of all normalised dimension scores
  # All dimensions score 0–10 EXCEPT RI which scores -10 to +10.
  # RI is normalised before weighting: ri_normalised = (ri_raw + 10) / 2
  # This maps [-10, +10] → [0, 10] so it weights consistently with other dimensions.
  # Example: RI raw -5.0 → normalised 2.5 (correctly penalises a depleting product)
  #          RI raw +6.0 → normalised 8.0 (correctly rewards a regenerative product)

  ri_normalisation_formula: "(ri_raw + 10) / 2"
  max_score: 10.0
  display_precision: 1               # show to one decimal place, e.g. 7.4

  # HIP mark eligibility thresholds (applied to final HIP Score)
  thresholds:
    hip_mark_standard:  6.0          # minimum score to carry the HIP mark
    hip_mark_silver:    7.5
    hip_mark_gold:      9.0          # ALSO requires ri_raw >= 6.0 (Regenerative tier)
    ri_gold_minimum:    6.0          # RI raw score floor for gold mark eligibility


# -----------------------------------------------------------------------------
# DIMENSIONS
# -----------------------------------------------------------------------------
# BASE WEIGHTS — these are the default dimensional weights used when no
# category_weight_profile matches the product. When a profile IS matched
# via category_type_mapping, the profile's weights override these defaults.
# See category_weight_profiles section below. Added v1.4 (RES-1206).
#
# Each dimension follows the same structure:
#   name, weight, score_range, description   — human-readable (used in methodology doc)
#   data_sources                             — free sources the LLM and researcher use
#   input_fields                             — what to look for in submitted product data
#   scoring_rubric                           — verbatim anchors included in the LLM prompt
#   llm_instructions                         — task framing sent at the top of each prompt
#   output_schema                            — JSON structure the LLM must return
#
# Dimensions marked [TO COMPLETE] have placeholder content — fill in before use.

dimensions:

  # ===========================================================================
  # 1. MATERIAL SCARCITY INDEX (MSI)  —  weight 20%
  # ===========================================================================
  MSI:
    name: "Material Scarcity Index"
    weight: 0.20
    score_range: [0, 10]

    description: >
      Measures how scarce or geographically concentrated the primary materials
      in the product are. High-scarcity materials — rare earth elements, cobalt,
      lithium, indium, gallium, tellurium — score low. Abundant, widely available
      materials — steel, aluminium (especially recycled), glass, commodity plastics,
      bio-based materials — score high. Single-country supply concentration is also
      penalised, as it amplifies scarcity risk regardless of total reserve size.

    data_sources:
      - name: "USGS Mineral Resources Program — Mineral Commodity Summaries"
        url: "https://www.usgs.gov/centers/national-minerals-information-center/mineral-commodity-summaries"
        licence: "Public Domain (US Federal Government)"
        use: >
          Annual reserve estimates, mine production by country, and supply-risk
          assessments for ~90 mineral commodities. The primary reference for
          'how scarce is this material globally?'

      - name: "EU Critical Raw Materials List (2023 update)"
        url: "https://single-market-economy.ec.europa.eu/sectors/raw-materials/areas-specific-interest/critical-raw-materials_en"
        licence: "EU Open Data (CC BY 4.0)"
        use: >
          Official EU list of materials with high economic importance and high
          supply risk. If a material appears on this list, treat it as high-scarcity
          regardless of other data. Updated approximately every 3 years.

    input_fields:
      # Fields the pipeline looks for in submitted product data (JSON).
      # If a field is missing, the pipeline uses assumed_default.
      # The LLM is told which fields were assumed vs submitted.

      - field: "primary_materials"
        description: >
          List of primary materials by common name.
          Examples: ["copper", "ABS plastic", "neodymium", "aluminium"]
        required: true
        assumed_default: "category_baseline_materials"
        # If not submitted, pipeline looks up category_baselines[product_type].MSI.primary_materials

      - field: "material_percentages"
        description: >
          Approximate percentage by weight for each listed material (optional).
          Improves score accuracy; if absent, pipeline treats all materials equally.
        required: false
        assumed_default: null

      - field: "recycled_content_pct"
        description: "Percentage of total product weight that is recycled content (0–100)."
        required: false
        assumed_default: 0
        # Conservative default: assume no recycled content unless submitted

      - field: "country_of_primary_extraction"
        description: >
          Country or countries where the dominant share of primary materials
          are extracted. Used to assess single-country supply concentration.
        required: false
        assumed_default: null
        # If absent, LLM uses known production geography from training knowledge

    scoring_rubric:
      # These anchor descriptions are included verbatim in the LLM prompt.
      # Be explicit — models need clear criteria, not vague guidance.
      # Each band is a range string mapped to a description.

      "0–2":
        label: "Critically Scarce"
        criteria: >
          Product relies heavily on materials on the EU Critical Raw Materials list
          or USGS high-supply-risk designations — for example cobalt, lithium,
          rare earth elements (neodymium, dysprosium, terbium), indium, gallium,
          or tellurium. High single-country supply concentration (more than 70%
          of global supply from one nation). Little or no recycled content.
          This score is expected for most conventional consumer electronics.

      "3–4":
        label: "Scarce"
        criteria: >
          Contains some critical or scarce materials but they are not dominant
          by weight or function. OR: primarily abundant materials but with
          significant single-country concentration risk. Recycled content
          below 20%. Slightly better than the worst case but still concerning.

      "5–6":
        label: "Moderate"
        criteria: >
          Mix of common and moderately scarce materials. No EU CRM-listed material
          dominates by weight. Some recycled content (20–40%) or supply diversity
          across multiple countries. Broadly average performance for the product
          category — not a cause for concern but no credit either.

      "7–8":
        label: "Low Scarcity"
        criteria: >
          Primarily abundant, widely available materials — steel, aluminium, glass,
          commodity plastics. No EU CRM-listed materials present, or only trace
          amounts that are functionally incidental. Recycled content above 40%.
          Good supply diversity across multiple countries.

      "9–10":
        label: "Exemplary"
        criteria: >
          All primary materials are abundant with no criticality flags whatsoever.
          High recycled content (above 60%) or bio-based / sustainably sourced
          materials. No single-country supply concentration risk. Sets the
          benchmark for the category.

    llm_instructions: >
      You are completing the Material Scarcity Index (MSI) dimension of a
      Resourcehip HIP (Human Impact Profile) sustainability assessment.

      Your task: read the product data provided, apply the scoring rubric below,
      and return a JSON object matching the output schema exactly.

      Rules:
      - Use ONLY the product data provided. Do not invent specific values.
      - Cross-reference materials against the EU Critical Raw Materials list
        and USGS high-supply-risk designations using your training knowledge.
      - Where input fields were assumed (not submitted by the manufacturer),
        score conservatively — when in doubt, score lower rather than higher.
      - Be specific in your justification: name the materials that drove the score.
      - Reply in valid JSON only. No prose, no markdown, no explanation outside
        the JSON object.

    output_schema:
      # The pipeline validates the LLM response against this schema.
      # If validation fails, the call is retried (up to max_retries times).
      type: object
      required: [score, justification, flags, assumed, assumed_fields]
      properties:
        score:
          type: number
          minimum: 0
          maximum: 10
          description: "MSI score to one decimal place (e.g. 3.5)"
        justification:
          type: string
          maxLength: 300
          description: >
            One to three plain-English sentences explaining the score.
            Name the specific materials or supply factors that drove it.
            This text appears on the public rating page.
        flags:
          type: array
          items:
            type: string
          description: >
            Specific concerns to display on the rating page.
            Examples: ["Cobalt — EU Critical Raw Materials list",
                       "China >80% of global rare earth supply"].
            Empty array [] if no specific flags.
        assumed:
          type: boolean
          description: "true if ANY input field was missing and a default was used."
        assumed_fields:
          type: array
          items:
            type: string
          description: >
            Names of fields that were assumed rather than submitted by the
            manufacturer. Empty array [] if all data was provided.
            Example: ["recycled_content_pct", "country_of_primary_extraction"]


  SCR:
    name: "Supply Chain Risk"
    weight: 0.18
    score_range: [0, 10]

    description: >
      Assesses how vulnerable the product's supply chain is to disruption.
      High-risk products depend on materials sourced from a small number of
      politically unstable countries, with no formal due-diligence programme
      and few viable alternative suppliers. Low-risk products draw from
      geographically diversified, politically stable sources with documented
      supplier audits and verified alternative procurement routes.

    data_sources:
      - name: "USGS Mineral Resources Program — Country Production Statistics"
        url: "https://www.usgs.gov/centers/national-minerals-information-center"
        licence: "Public Domain (US Federal Government)"
        use: >
          Country-level mine production data for ~90 commodities. Primary source
          for identifying single-country production concentration (e.g. China >80%
          of rare earths, DRC >70% of cobalt).

      - name: "World Bank Worldwide Governance Indicators (WGI)"
        url: "https://info.worldbank.org/governance/wgi/"
        licence: "CC BY 4.0"
        use: >
          Political stability and rule-of-law scores by country. Used to convert
          production-concentration data into geopolitical risk scores. A country
          producing >50% of a key material and scoring below 40th percentile on
          political stability is treated as a high-risk concentration.

      - name: "EU Critical Raw Materials — Supply Risk Scores"
        url: "https://single-market-economy.ec.europa.eu/sectors/raw-materials/areas-specific-interest/critical-raw-materials_en"
        licence: "EU Open Data (CC BY 4.0)"
        use: >
          EU supply risk methodology uses Herfindahl-Hirschman Index (HHI)
          concentration scores. Materials with EU supply risk score >1 are treated
          as high SCR risk regardless of other factors.

      - name: "OECD Country Risk Classifications"
        url: "https://www.oecd.org/trade/topics/export-credits/documents/understanding-the-country-risk-classification.htm"
        licence: "OECD Terms (free for non-commercial research)"
        use: >
          Country risk classification 0–7 used as a proxy for geopolitical
          supply risk. Countries rated 5–7 are high-risk; materials primarily
          sourced from these countries score in the 0–3 SCR range.

    input_fields:
      - field: "primary_sourcing_countries"
        description: >
          Country or countries where the dominant share of key materials
          are mined or processed. Provide as a list.
          Example: ["China", "DRC", "Chile"]
        required: false
        assumed_default: null
        # If absent, LLM uses known production geography from training knowledge
        # based on material types identified in primary_materials (MSI field).

      - field: "tier1_supplier_count"
        description: >
          Number of independent tier-1 suppliers for the product's primary
          material inputs. A single supplier or a single country of origin
          for any critical material is high risk.
        required: false
        assumed_default: 1
        # Conservative: assume single-supplier dependency if not stated.

      - field: "due_diligence_standard"
        description: >
          Named supply-chain due diligence standard the manufacturer follows.
          Accepted values: "OECD", "RBA" (Responsible Business Alliance),
          "ISO 20400", "SA8000", or null if none.
        required: false
        assumed_default: null

      - field: "alternative_supplier_exists"
        description: >
          Boolean — does the manufacturer have a verified alternative supplier
          for their primary material inputs? True only if formally documented.
        required: false
        assumed_default: false

    scoring_rubric:
      "0-2":
        label: "Critical Risk"
        criteria: >
          One or more primary materials sourced predominantly (>60% global supply)
          from a single country rated high-risk by OECD (category 5-7) or WGI
          political stability below 25th percentile. OR: material on EU Critical
          Raw Materials list with EU supply risk score >2. No due-diligence
          programme in place. No alternative supplier documented.
          Examples: cobalt from DRC with no RBA audit; rare earths from China
          with no diversification programme.

      "3-4":
        label: "High Risk"
        criteria: >
          Primary materials have meaningful concentration risk (40-60% from one
          country) or sourced from moderate-risk countries (OECD category 3-4).
          Due-diligence may be claimed but not third-party verified. Single
          primary supplier with no documented alternative.
          Hair dryer baseline: copper and nichrome fit here — concentration risk
          is real but alternatives exist in principle.

      "5-6":
        label: "Moderate Risk"
        criteria: >
          Key materials sourced from two or more countries with acceptable
          governance scores (OECD 0-2, WGI above 40th percentile). Some
          due-diligence framework referenced (OECD or RBA) even if not
          independently audited. At least one documented alternative supplier.
          No material on EU CRM list dominates by weight.

      "7-8":
        label: "Low Risk"
        criteria: >
          Supply chain geographically diversified across three or more countries,
          all with stable governance scores. Formal due-diligence programme
          implemented and third-party audited (RBA, ISO 20400, or equivalent).
          Multiple verified alternative suppliers for all primary material inputs.

      "9-10":
        label: "Resilient"
        criteria: >
          All primary materials sourced from politically stable, low-risk
          jurisdictions with full governance transparency. Supply chain fully
          mapped to raw material origin. Independent annual audit of due-diligence
          programme. No EU CRM-listed materials without verified alternative
          procurement routes. Sets the benchmark for supply chain resilience.

    llm_instructions: >
      You are completing the Supply Chain Risk (SCR) dimension of a Resourcehip
      HIP (Human Impact Profile) sustainability assessment.

      Your task: read the product data provided, apply the scoring rubric, and
      return a JSON object matching the output schema exactly.

      Rules:
      - Use ONLY the product data provided. Do not invent supplier details.
      - Where sourcing countries are not submitted, use your training knowledge
        of typical production geography for the materials identified in the
        product's primary_materials list.
      - Score conservatively: where due diligence is claimed but not verified,
        award partial credit only (maximum 6).
      - Be specific in your justification: name the materials, countries, and
        risk factors that drove the score.
      - Reply in valid JSON only. No prose outside the JSON object.

      Expected SCR ranges by product type (sanity check):
        - Consumer electronics with rare earth content (no audit): 1-3
        - Standard appliances (copper, steel, plastics, no audit): 3-5
        - Products with verified RBA or OECD audit: 5-7
        - Products with full supply chain transparency and diversification: 7-9

    output_schema:
      type: object
      required: [score, justification, flags, assumed, assumed_fields]
      properties:
        score:
          type: number
          minimum: 0
          maximum: 10
          description: "SCR score to one decimal place (e.g. 3.5)"
        justification:
          type: string
          maxLength: 300
          description: >
            One to three plain-English sentences explaining the score.
            Name specific countries, materials, and risk factors.
            This text appears on the public rating page.
        flags:
          type: array
          items:
            type: string
          description: >
            Specific supply-chain risk flags to display on the rating page.
            Examples: ["Cobalt — DRC >70% global supply, OECD risk category 6",
                       "No due-diligence programme documented"].
            Empty array [] if no specific flags.
        assumed:
          type: boolean
          description: "true if ANY input field was missing and a default was used."
        assumed_fields:
          type: array
          items:
            type: string
          description: "Fields assumed rather than submitted. Empty array [] if all provided."

  RC:
    name: "Recyclability and Circularity"
    weight: 0.18
    score_range: [0, 10]

    description: >
      Measures how effectively materials in the product can be recovered and
      re-entered into productive use at end of life. The key distinction is
      practical recyclability — whether the recycling infrastructure actually
      exists and is used — rather than theoretical recyclability based on
      material properties alone. A product made of technically recyclable
      materials that are routinely landfilled in practice scores no higher
      than a product with genuinely recoverable streams. Design choices that
      aid disassembly, clear labelling, and manufacturer take-back schemes
      all contribute positively.

    data_sources:
      - name: "Ellen MacArthur Foundation — Circular Economy Resources"
        url: "https://ellenmacarthurfoundation.org/topics/circular-economy-introduction/overview"
        licence: "Public (research use)"
        use: >
          Circular economy metrics, material flow data, and case studies on
          design-for-circularity. Reference for what genuine circularity looks
          like in practice at product category level.

      - name: "UK WRAP — Recycling and Resource Management"
        url: "https://www.wrap.ngo"
        licence: "Open Government Licence v3.0"
        use: >
          UK-specific data on which material streams are accepted by kerbside
          collections, recycling rates by material, and guidance on recyclability
          labelling. Used to assess whether stated recyclability reflects
          real infrastructure availability.

      - name: "European Recycling Industries' Confederation (EuRIC)"
        url: "https://www.euric-aisbl.eu"
        licence: "Public (research use)"
        use: >
          European recycled material stream data by category. Used to validate
          claims about material recovery rates for electronics, plastics, metals,
          and packaging at EU scale.

      - name: "BS EN 45555 — General Methods for the Assessment of the Ability to Reuse, Recycle and Recover Electrical and Electronic Equipment"
        url: "https://knowledge.bsigroup.com/products/general-methods-for-the-assessment-of-the-ability-to-reuse-recycle-and-recover-electrical-and-electronic-equipment"
        licence: "Paid standard — reference methodology only, do not reproduce"
        use: >
          European standard methodology for assessing recyclability of electrical
          products. Use the methodology as a framework; the score thresholds in
          the standard provide calibration for the scoring rubric.

    input_fields:
      - field: "disassembly_type"
        description: >
          Primary method by which the product is held together.
          Accepted values: "screws", "clips", "mixed_screws_clips",
          "glued", "ultrasonically_welded", "modular".
          "modular" indicates intentional design-for-disassembly.
        required: false
        assumed_default: "glued"
        # Conservative: assume hardest to disassemble if not stated.

      - field: "recyclable_streams_pct"
        description: >
          Estimated percentage by weight of the product that enters a
          PRACTICAL recycling stream at end of life (not theoretical).
          For example, copper wiring has high recovery value and is
          practically recycled; ABS plastic from small appliances typically
          is not recovered in practice even though it is technically recyclable.
        required: false
        assumed_default: 20
        # Conservative: most mixed small appliances recover only the metal streams.

      - field: "recycling_label_compliant"
        description: >
          Boolean — does the product carry correct recycling labelling
          (e.g. Mobius loop where appropriate, WEEE symbol for electronics,
          material identification codes on plastics)?
        required: false
        assumed_default: false

      - field: "takeback_scheme"
        description: >
          Boolean — does the manufacturer operate a verified take-back or
          extended producer responsibility (EPR) programme for this product?
        required: false
        assumed_default: false

      - field: "design_for_disassembly"
        description: >
          Boolean — has the product been explicitly designed for disassembly,
          with publicly documented disassembly instructions and separated
          material streams?
        required: false
        assumed_default: false

    scoring_rubric:
      "0-2":
        label: "Non-Recyclable"
        criteria: >
          Product is glued, ultrasonically welded, or otherwise designed in a
          way that makes material separation impractical without specialist
          equipment. Less than 20% by weight enters any practical recycling stream.
          No recycling labelling. No take-back scheme.
          Examples: cheap consumer electronics with fully sealed housings;
          composite materials that cannot be separated.

      "3-4":
        label: "Poorly Recyclable"
        criteria: >
          Mixed fastener types (some screws, some glue) make disassembly
          time-consuming. 20-40% by weight practically recoverable — typically
          just the metal components. Some recycling labelling present.
          No take-back scheme. Represents the typical mass-market small appliance.
          Hair dryer baseline: copper wiring and motor recovered, ABS and nichrome
          largely not — sits at the lower end of this band.

      "5-6":
        label: "Partially Recyclable"
        criteria: >
          Disassembly achievable with standard tools (all screws or all clips).
          40-60% by weight enters practical recycling streams. Clear and correct
          recycling labelling on product and packaging. No take-back scheme,
          but material streams are accepted by standard recycling infrastructure
          in major markets.

      "7-8":
        label: "Well-Designed for Recovery"
        criteria: >
          Product disassembles cleanly into separated material streams (screws
          throughout, no glue). 60-80% by weight practically recoverable.
          Correct labelling. Manufacturer take-back scheme in operation with
          verified recovery rates, OR certified to EN 45555 recyclability
          requirements. Materials identified with codes at component level.

      "9-10":
        label: "Circular"
        criteria: >
          Designed explicitly for disassembly and material recovery. Greater
          than 80% by weight enters verified recycling streams. Product is
          modular — components can be replaced individually. Public disassembly
          instructions available. Verified take-back or EPR programme.
          Manufacturer publishes annual recovery rate data. Sets the benchmark
          for circular product design in its category.

    llm_instructions: >
      You are completing the Recyclability and Circularity (RC) dimension of a
      Resourcehip HIP (Human Impact Profile) sustainability assessment.

      CRITICAL DISTINCTION: Score for PRACTICAL recyclability only — whether
      recycling infrastructure exists and is used in practice. A material
      that is technically recyclable but is routinely landfilled in the real
      world (e.g. ABS plastic from small appliances, nichrome heating elements)
      does NOT count as practically recyclable. Apply this test rigorously.

      Rules:
      - Use ONLY the product data provided.
      - Score conservatively: theoretical recyclability without infrastructure
        evidence counts for nothing above the baseline.
      - If disassembly_type is not submitted, assume "glued" (worst case).
      - If recyclable_streams_pct is not submitted, estimate from the product
        type and materials: typically only metal components are practically
        recovered from small appliances without a take-back scheme.
      - Reply in valid JSON only. No prose outside the JSON object.

      Expected RC ranges by product type (sanity check):
        - Sealed consumer electronics, no take-back scheme: 1-3
        - Standard small appliances (screws, metal streams): 3-5
        - Appliances with take-back scheme and labelling: 5-7
        - Products certified to EN 45555 or equivalent: 6-8
        - Fully modular with verified >80% recovery: 8-10

    output_schema:
      type: object
      required: [score, justification, flags, assumed, assumed_fields]
      properties:
        score:
          type: number
          minimum: 0
          maximum: 10
          description: "RC score to one decimal place."
        justification:
          type: string
          maxLength: 300
          description: >
            One to three plain-English sentences explaining the score.
            Distinguish between theoretical and practical recyclability.
            This text appears on the public rating page.
        flags:
          type: array
          items:
            type: string
          description: >
            Specific recyclability concerns to display.
            Examples: ["ABS plastic — not recovered from small appliances in practice",
                       "Nichrome heating element — no commercial recycling stream"].
            Empty array [] if no specific flags.
        assumed:
          type: boolean
          description: "true if ANY input field was missing and a default was used."
        assumed_fields:
          type: array
          items:
            type: string
          description: "Fields assumed rather than submitted. Empty array [] if all provided."

  R:
    name: "Repairability"
    weight: 0.13
    score_range: [0, 10]

    description: >
      Scores how easily a product can be repaired by the owner or an
      independent repairer, extending useful life and deferring replacement.
      Key indicators are fastener type (screws versus glue), availability of
      spare parts from the manufacturer or third parties, access to service
      documentation, and iFixit repairability score where one exists.
      EU Ecodesign right-to-repair regulations mandate minimum standards for
      certain product categories; products in scope are assessed against those
      requirements. Products outside scope are assessed against the same
      criteria without the regulatory baseline assumption.

    data_sources:
      - name: "iFixit Repairability Database"
        url: "https://www.ifixit.com/repairability"
        licence: "Public (check scraping policy before automating requests)"
        use: >
          Standardised repairability scores (0-10) for hundreds of consumer
          electronics and appliances. The iFixit score uses the same 0-10
          scale as Resourcehip and is directly mappable. Where an iFixit score
          exists for the specific product or a close equivalent, weight it
          heavily in the assessment.

      - name: "EU Right to Repair Directive (EU) 2024/1799 & Ecodesign for Sustainable Products Regulation (EU) 2024/1781"
        url: "https://eur-lex.europa.eu/eli/dir/2024/1799/oj"
        licence: "EU Law (public)"
        use: >
          Right to Repair Directive (EU) 2024/1799 (in force 30 Jul 2024,
          applies from 31 Jul 2026) mandates repair beyond warranty at a
          reasonable price and time for the Annex II product set: household
          washing machines and washer-dryers, dishwashers, refrigerating
          appliances, vacuum cleaners, electronic displays, mobile phones,
          cordless phones, tablets, and servers. Product-specific spare-parts
          and repairability floors are set in ESPR (EU) 2024/1781 implementing
          and delegated acts — which supersede the former Ecodesign Directive
          2009/125/EC — e.g. Reg (EU) 2019/2023 (washing machines) and Reg (EU)
          2019/2019 (refrigerators), as amended by Reg (EU) 2021/341. In-scope
          products must supply spare parts for the minimum period set in the
          applicable act (typically 7-10 years) and provide service information
          to professional repairers. Use to establish the regulatory baseline
          for in-scope products.

      - name: "Right to Repair Europe — Product Category Reports"
        url: "https://repair.eu/resources/"
        licence: "Public (research use)"
        use: >
          Campaign documentation including repairability benchmarks for product
          categories not yet covered by EU regulations. Useful for calibrating
          scores for products outside current Ecodesign scope.

    input_fields:
      - field: "fastener_type"
        description: >
          Primary fastener type used in product construction.
          Accepted values: "standard_screws", "proprietary_screws",
          "clips_only", "mixed_screws_clips", "glued", "ultrasonically_welded".
          "standard_screws" means Phillips, Torx, or flathead — any screwdriver
          a consumer or repairer would own.
        required: false
        assumed_default: "glued"
        # Conservative: assume hardest to open if not stated.

      - field: "spare_parts_available"
        description: >
          Boolean — does the manufacturer supply spare parts (e.g. heating
          elements, motors, batteries, filters) through their website or
          through independent distributors?
        required: false
        assumed_default: false

      - field: "spare_parts_years_committed"
        description: >
          Number of years from product launch for which the manufacturer
          commits to supplying spare parts. EU Ecodesign minimum is 7-10 years
          depending on product category.
        required: false
        assumed_default: 0

      - field: "service_manual_public"
        description: >
          Boolean — is a service or repair manual publicly available (not
          restricted to authorised service centres only)?
        required: false
        assumed_default: false

      - field: "ifixit_score"
        description: >
          iFixit repairability score (0-10) for this product or a directly
          comparable model. Null if no iFixit score exists.
        required: false
        assumed_default: null

      - field: "ecodesign_in_scope"
        description: >
          Boolean — is this product category subject to binding EU
          repairability / spare-parts obligations, i.e. listed in Annex II of
          the Right to Repair Directive (EU) 2024/1799, or covered by an ESPR
          (EU) 2024/1781 product-specific implementing/delegated act currently
          in force? (Formerly anchored to Ecodesign Reg 2021/341.)
        required: false
        assumed_default: false

    scoring_rubric:
      "0-2":
        label: "Unrepairable"
        criteria: >
          Product is glued or ultrasonically welded shut. No spare parts
          available from manufacturer or third parties. No service manual.
          No iFixit score, or iFixit score below 3. Typical of sealed consumer
          electronics, fashion accessories, and disposable appliances.
          Designed to be replaced, not repaired.

      "3-4":
        label: "Difficult to Repair"
        criteria: >
          Mixed fasteners — some screws but also adhesive or clips making
          full disassembly destructive or difficult. Limited spare parts
          available (e.g. accessories only, not internal components).
          No public service manual. iFixit score 3-5 if available.
          Represents most mass-market small appliances including standard
          hair dryers — technically possible to open but not designed for it.

      "5-6":
        label: "Repairable with Effort"
        criteria: >
          Primarily screw-fastened with standard bits. Some spare parts
          available (heating elements, filters, or key wear components).
          No public service manual but repair communities have documented
          the product. iFixit score 5-6 if available. Independent repair
          is possible for a skilled user but not designed to be straightforward.

      "7-8":
        label: "Designed for Repair"
        criteria: >
          All standard screws, no adhesive on functional assemblies. Key spare
          parts (motor, heating element, battery, filter) available directly
          from manufacturer for minimum 5 years post-purchase. Public service
          manual or iFixit score of 7-8. OR: product is within EU Ecodesign
          scope and meets minimum regulatory requirements. Independent repair
          is genuinely practical.

      "9-10":
        label: "Exemplary Repairability"
        criteria: >
          Fully screw-fastened, no glue on any functional component. Full
          spare parts programme for minimum 10 years committed in writing.
          Comprehensive public service manual. iFixit score 8-10 or equivalent
          third-party repairability certification. Modular design allowing
          component-level replacement. Meets or exceeds EU Ecodesign requirements
          regardless of whether the product is in scope. Sets the benchmark
          for repairability in its category.

    llm_instructions: >
      You are completing the Repairability (R) dimension of a Resourcehip
      HIP (Human Impact Profile) sustainability assessment.

      Your task: read the product data provided, apply the scoring rubric, and
      return a JSON object matching the output schema exactly.

      Rules:
      - Use ONLY the product data provided.
      - If an iFixit score exists for this specific product or a close equivalent,
        use it as a primary anchor — it uses the same 0-10 scale.
      - Score conservatively: if fastener_type is unknown, assume "glued".
        If spare_parts_available is unknown, assume false.
      - EU Ecodesign compliance is a floor, not a ceiling: meeting regulatory
        minimums scores approximately 6-7, not 9-10.
      - Hair dryers are NOT currently within EU Ecodesign right-to-repair scope.
        Apply the rubric criteria directly with no regulatory baseline assumption.
      - Reply in valid JSON only. No prose outside the JSON object.

      Expected R ranges by product type (sanity check):
        - Typical sealed consumer electronics: 1-3
        - Standard mass-market small appliances (no parts, no manual): 2-4
        - Appliances with some parts available: 4-6
        - Products within EU Ecodesign scope meeting minimums: 6-7
        - Premium products with full parts programme and manual: 7-9
        - Products explicitly designed for repair (iFixit 8+): 8-10

    output_schema:
      type: object
      required: [score, justification, flags, assumed, assumed_fields]
      properties:
        score:
          type: number
          minimum: 0
          maximum: 10
          description: "R score to one decimal place."
        justification:
          type: string
          maxLength: 300
          description: >
            One to three plain-English sentences explaining the score.
            Reference the fastener type, parts availability, and any iFixit score.
            This text appears on the public rating page.
        flags:
          type: array
          items:
            type: string
          description: >
            Specific repairability concerns to display.
            Examples: ["Glued housing — not openable without damage",
                       "No spare parts programme — manufacturer-replace only"].
            Empty array [] if no specific flags.
        assumed:
          type: boolean
          description: "true if ANY input field was missing and a default was used."
        assumed_fields:
          type: array
          items:
            type: string
          description: "Fields assumed rather than submitted. Empty array [] if all provided."

  SEI:
    name: "Social and Environmental Impact"
    weight: 0.08
    score_range: [0, 10]

    description: >
      Captures labour practices, environmental management, and community impacts
      across the manufacturing supply chain. This is the dimension hardest to
      verify from public data alone — a score above 5 requires submitted evidence
      of third-party audit or certification. Without manufacturer submission, the
      pipeline applies conservative assumptions based on known manufacturing
      geography and sector risk profiles. The low weight (9%) reflects this
      verification challenge while still ensuring social and environmental
      performance contributes meaningfully to the overall HIP Score.

    data_sources:
      - name: "OECD Due Diligence Guidance for Responsible Mineral Supply Chains"
        url: "https://www.oecd.org/corporate/mne/mining.htm"
        licence: "OECD Terms (free for non-commercial research)"
        use: >
          The primary framework for assessing whether manufacturers have formal
          due diligence processes covering labour, environment, and community
          impacts in their mineral supply chains. Five-step framework used as
          reference for what 'adequate due diligence' means.

      - name: "ILO International Labour Standards — Decent Work Indicators"
        url: "https://www.ilo.org/global/standards/lang--en/index.htm"
        licence: "Public"
        use: >
          ILO core conventions (child labour, forced labour, freedom of
          association, non-discrimination) as the baseline for acceptable
          labour practice. Manufacturing in countries with weak ILO convention
          ratification and poor enforcement is treated as elevated risk.

      - name: "Responsible Business Alliance (RBA) — Code of Conduct"
        url: "https://www.responsiblebusiness.org/code-of-conduct/"
        licence: "Public (research use)"
        use: >
          Electronics sector standard for factory audits covering labour,
          health and safety, environment, ethics, and management systems.
          RBA membership and audit completion is treated as meaningful third-party
          verification for manufacturing practices.

      - name: "Business and Human Rights Resource Centre"
        url: "https://www.business-humanrights.org"
        licence: "Public"
        use: >
          Sector-level and company-level risk data for human rights and
          environmental abuses in supply chains. Used to identify flagged
          companies or sourcing regions with documented adverse impacts.

    input_fields:
      - field: "manufacturing_countries"
        description: >
          Country or countries where the product is primarily assembled
          or manufactured. Provide as a list.
          Example: ["China", "Vietnam"]
        required: false
        assumed_default: ["China"]
        # Conservative: China is the most common default for consumer electronics
        # and appliances. Moderate risk profile, not high risk.

      - field: "environmental_certifications"
        description: >
          List of environmental management certifications held by the
          manufacturer or primary factory.
          Examples: ["ISO 14001", "B Corp", "EMAS", "SA8000"]
          Empty list [] if none.
        required: false
        assumed_default: []

      - field: "third_party_certification"
        description: >
          Name of a third-party certification held (e.g. "ISO 14001:2015",
          "B Corp"). Null if none. Third-party (not self-declared) is the
          key property — treat self-attestations with lower weight.
        required: false
        assumed_default: null

      - field: "rba_audit_completed"
        description: >
          Boolean — has the primary manufacturing facility completed a
          Responsible Business Alliance (RBA) audit within the past 2 years?
        required: false
        assumed_default: false

      - field: "modern_slavery_statement"
        description: >
          Boolean — does the manufacturer publish an annual Modern Slavery
          Act statement (required for UK companies with turnover >£36m,
          but a positive signal for any size company)?
        required: false
        assumed_default: false

      - field: "ilo_compliance_claimed"
        description: >
          Boolean — does the manufacturer formally claim compliance with ILO
          core conventions across their supply chain (in writing, in their
          supplier code of conduct or annual report)?
        required: false
        assumed_default: false

    scoring_rubric:
      "0-2":
        label: "Significant Risk"
        criteria: >
          Manufacturing in countries with documented high risk of labour abuses
          or environmental violations and no evidence of mitigation. No
          certifications, no audit, no due-diligence programme. Business and
          Human Rights Resource Centre flags specific adverse impacts for the
          company or its key suppliers. ILO core conventions not ratified or
          poorly enforced in manufacturing country.

      "3-4":
        label: "Elevated Risk — Unverified"
        criteria: >
          Manufacturing in moderate-to-high risk jurisdictions (e.g. China,
          Bangladesh, Cambodia) with no third-party audit evidence. ILO
          compliance may be claimed but is not independently verified.
          No environmental management certification. This is the appropriate
          baseline for most mass-market consumer goods manufactured in Asia
          with no submitted sustainability evidence.

      "5-6":
        label: "Baseline Compliance"
        criteria: >
          Manufacturing in moderate-risk jurisdiction with at least one
          meaningful indicator of managed risk: ISO 14001 environmental
          management certification, annual modern slavery statement, or
          formal supplier code of conduct aligned to ILO standards.
          No third-party audit of labour practices but self-assessment
          processes documented.

      "7-8":
        label: "Verified Good Practice"
        criteria: >
          RBA audit completed within past 2 years at primary manufacturing
          facility, OR B Corp certification held. Manufacturing in lower-risk
          jurisdiction (OECD member with strong labour law enforcement) OR
          credible third-party supply chain audit in place. Modern slavery
          statement published annually. Environmental management system
          certified (ISO 14001 or EMAS).

      "9-10":
        label: "Exemplary"
        criteria: >
          Full supply chain transparency to raw material origin for all
          primary materials. Multiple independent audits (RBA, SA8000 or
          equivalent) with results published. Manufacturing in jurisdiction
          with strong labour law enforcement. B Corp or equivalent holistic
          certification covering environmental and social performance.
          Evidence of community benefit programmes linked to manufacturing
          or sourcing locations. No adverse findings in Business and Human
          Rights Resource Centre database.

    llm_instructions: >
      You are completing the Social and Environmental Impact (SEI) dimension
      of a Resourcehip HIP (Human Impact Profile) sustainability assessment.

      CRITICAL: This is the hardest dimension to score from public data.
      Apply a strict verification standard — a score above 5 requires
      submitted evidence of third-party audit or certification. Do not
      award more than 5 based on self-reported claims alone.

      Rules:
      - Use ONLY the product data provided.
      - If manufacturing_countries is not submitted, assume ["China"] —
        moderate risk, not a worst-case assumption but not positive.
      - Claims of ILO compliance or ethical sourcing that are not backed
        by an audit certificate or recognised certification cap the score
        at 5 maximum.
      - Be specific: if the score is low, name the risk factors (country,
        absence of audit). If the score is higher, name the certifications
        or audits that justified it.
      - Reply in valid JSON only. No prose outside the JSON object.

      Expected SEI ranges by product type (sanity check):
        - No certifications, manufactured in Asia (assumed): 3-5
        - ISO 14001 or modern slavery statement only: 4-6
        - RBA audit completed: 5-7
        - B Corp certified manufacturer: 6-8
        - Full supply chain transparency, multiple audits: 8-10

    output_schema:
      type: object
      required: [score, justification, flags, assumed, assumed_fields]
      properties:
        score:
          type: number
          minimum: 0
          maximum: 10
          description: "SEI score to one decimal place."
        justification:
          type: string
          maxLength: 300
          description: >
            One to three plain-English sentences explaining the score.
            State what evidence was present or absent. This appears on the
            public rating page.
        flags:
          type: array
          items:
            type: string
          description: >
            Specific social or environmental risk flags.
            Examples: ["No third-party labour audit submitted",
                       "Manufacturing country — elevated labour risk profile"].
            Empty array [] if no specific flags.
        assumed:
          type: boolean
          description: "true if ANY input field was missing and a default was used."
        assumed_fields:
          type: array
          items:
            type: string
          description: "Fields assumed rather than submitted. Empty array [] if all provided."

  PL:
    name: "Product Longevity"
    weight: 0.08
    score_range: [0, 10]

    description: >
      Assesses the expected useful lifespan of the product and the design
      choices that extend or limit it. A longer-lived product defers
      replacement, reducing the cumulative resource and manufacturing burden
      per year of use. Key indicators are the manufacturer's stated warranty
      period, publicly committed design life, environmental protection ratings
      (IP rating for dust and water resistance), modular or repairable design
      as a proxy for design intent, and — for connected products — the
      software and firmware support horizon after which the product may
      become non-functional.

    data_sources:
      - name: "EU Ecodesign Product-Specific Regulations"
        url: "https://energy.ec.europa.eu/topics/energy-efficiency/energy-efficient-products/ecodesign-sustainable-products-regulation_en"
        licence: "EU Law (public)"
        use: >
          Some Ecodesign implementing measures specify minimum warranty and
          spare-parts availability periods. Use these as reference floors for
          products in scope. Where no Ecodesign regulation applies to the
          category, use industry averages as the baseline.

      - name: "European Consumer Organisation (BEUC) — Product Lifespan Research"
        url: "https://www.beuc.eu/durability"
        licence: "Public (research use)"
        use: >
          Research on expected and actual product lifespans by category across
          EU markets. Use for calibrating what 'average', 'above average', and
          'below average' lifespan means for the specific product type.

      - name: "Which? Product Reliability Surveys"
        url: "https://www.which.co.uk/reviews/reliability"
        licence: "Subscription (reference to methodology only — do not reproduce data)"
        use: >
          UK-specific product reliability data by brand and category.
          Used as a reference for expected lifespan benchmarks. Note:
          subscription required — use only to calibrate category norms,
          do not reproduce specific scores.

    input_fields:
      - field: "warranty_years"
        description: >
          Manufacturer's stated warranty period in years at point of sale
          in the UK/EU market. The statutory minimum in the EU is 2 years;
          longer warranties are a positive signal.
        required: false
        assumed_default: 1
        # Conservative: 1 year reflects the UK statutory minimum.
        # EU mandatory minimum is 2 years — if product is EU-marketed and
        # warranty_years is not submitted, use 2 as the assumed default instead.

      - field: "stated_design_life_years"
        description: >
          Manufacturer's publicly committed design life or expected lifespan
          in years. Only count if stated explicitly in product documentation
          or technical specifications — not marketing language.
        required: false
        assumed_default: null
        # If not stated, estimate from category norms using BEUC data.

      - field: "ip_rating"
        description: >
          IEC 60529 ingress protection rating (e.g. "IPX4", "IP67", "IP44").
          Null if not rated. Any IP rating is a positive signal as it indicates
          designed-for-durability against environmental ingress.
        required: false
        assumed_default: null

      - field: "modular_design"
        description: >
          Boolean — is the product designed with replaceable modules (e.g.
          swappable battery, user-replaceable filter, separate power supply)?
          This is distinct from repairability — modularity implies the
          manufacturer intended component-level life extension.
        required: false
        assumed_default: false

      - field: "software_support_years"
        description: >
          For connected or smart products only: number of years from product
          launch for which the manufacturer commits to software and security
          updates. Null for non-connected products — field is not applicable.
        required: false
        assumed_default: null

    scoring_rubric:
      "0-2":
        label: "Disposable"
        criteria: >
          Warranty of 1 year or less. No stated design life, or stated design
          life below 3 years. No IP rating. No modular design. Product is
          designed or priced to be replaced rather than maintained. For connected
          products: software support less than 2 years from launch.
          Examples: ultra-low-cost appliances, fashion electronics, single-season
          products.

      "3-4":
        label: "Below Average Lifespan"
        criteria: >
          Warranty of 1-2 years (meets legal minimums but no more). Estimated
          design life 3-5 years based on category norms. No IP rating.
          No modular design. Some repairability but no commitment to long-term
          parts availability. Represents the typical mass-market small appliance.
          Hair dryer baseline: 1-2 year warranty, 5-7 year real-world life,
          no IP rating, no modules — sits at the upper end of this band.

      "5-6":
        label: "Average Lifespan"
        criteria: >
          Warranty of 2-3 years. Estimated or stated design life 5-8 years.
          May have splash-resistant IP rating (IPX2-IPX4) suited to use
          environment. No modular design but standard fasteners support
          repair. For connected products: software support 2-4 years from launch.

      "7-8":
        label: "Above Average Lifespan"
        criteria: >
          Warranty of 3-5 years, OR manufacturer explicitly commits to
          spare-parts availability for minimum 7 years. Stated design life
          8-12 years backed by technical specification. Meaningful IP rating
          (IPX4 or higher, or IP5X dust resistance) appropriate to use
          environment. Modular or component-replaceable design. For connected
          products: software support 5-7 years from launch.

      "9-10":
        label: "Designed for Life"
        criteria: >
          Warranty of 5 or more years. Publicly committed design life of 10+
          years with technical evidence (accelerated lifecycle testing,
          MTTF data, or equivalent). High IP rating (IP67 or above for
          relevant use environments). Fully modular — all key wear components
          user-replaceable. For connected products: software support 7+
          years committed in writing, with planned hardware-agnostic
          software architecture. Product is clearly designed to outlast
          the market norm.

    llm_instructions: >
      You are completing the Product Longevity (PL) dimension of a Resourcehip
      HIP (Human Impact Profile) sustainability assessment.

      Your task: read the product data provided, apply the scoring rubric, and
      return a JSON object matching the output schema exactly.

      Rules:
      - Use ONLY the product data provided.
      - If warranty_years is not submitted, assume 1 year (UK conservative
        default). If product is clearly EU-marketed, assume 2 years.
      - If stated_design_life_years is not submitted, estimate from category
        norms: hair dryers typically 5-7 years; washing machines 10-12 years;
        smartphones 3-5 years. Use BEUC benchmarks as reference.
      - software_support_years only applies to connected/smart products.
        For non-connected products, leave this factor out of the assessment.
      - Score conservatively: a 2-year warranty alone is not sufficient for
        a score above 5 — design-life evidence is required.
      - Reply in valid JSON only. No prose outside the JSON object.

      Expected PL ranges by product type (sanity check):
        - Disposable or ultra-low-cost items: 1-2
        - Typical mass-market small appliances: 3-5
        - Mid-range with reasonable warranty: 4-6
        - Premium appliances with long warranty and parts programme: 6-8
        - Products explicitly designed for multi-decade life: 8-10

    output_schema:
      type: object
      required: [score, justification, flags, assumed, assumed_fields]
      properties:
        score:
          type: number
          minimum: 0
          maximum: 10
          description: "PL score to one decimal place."
        justification:
          type: string
          maxLength: 300
          description: >
            One to three plain-English sentences explaining the score.
            Reference the warranty, design life estimate, and any IP rating.
            This text appears on the public rating page.
        flags:
          type: array
          items:
            type: string
          description: >
            Specific longevity concerns or positive signals to display.
            Examples: ["1-year warranty only — below EU mandatory minimum",
                       "No stated design life — estimated from category norms"].
            Empty array [] if no specific flags.
        assumed:
          type: boolean
          description: "true if ANY input field was missing and a default was used."
        assumed_fields:
          type: array
          items:
            type: string
          description: "Fields assumed rather than submitted. Empty array [] if all provided."

  # ===========================================================================
  # 7. REGENERATIVE INDEX (RI)  —  weight 15%  — UNIQUE: scores -10 to +10
  # ===========================================================================
  RI:
    name: "Regenerative Index"
    weight: 0.15
    score_range: [-10, 10]           # THE ONLY DIMENSION WITH A NEGATIVE FLOOR
    normalisation_formula: "(ri_raw + 10) / 2"
    # This maps the -10 to +10 range onto 0 to 10 for consistent HIP Score weighting.
    # A product scoring RI -5.0 (Extractive) contributes ri_normalised 2.5 to the HIP Score.
    # A product scoring RI +6.0 (Regenerative) contributes ri_normalised 8.0.

    description: >
      The Regenerative Index is Resourcehip's unique dimension — no other mainstream
      sustainability rating uses a below-zero floor or distinguishes between depleting,
      neutral, and regenerative material flows.

      Negative scores (-10 to -1): primary production of key materials is actively
      depleting finite natural reserves with no credible regenerative pathway.
      Most conventional manufactured goods will score in the -8 to -4 range.
      This is not a failure — it is an honest baseline that creates the incentive
      to improve.

      Zero (Renewable): the product uses materials that are renewable and sustainably
      managed but not actively restoring natural capital. Certified timber,
      natural fibres from well-managed sources.

      Positive scores (+1 to +10): materials or production processes actively restore
      natural capital — regenerative agriculture inputs, verified sequestration,
      closed-loop manufacturing returning nutrients to land or water systems.
      Gold HIP mark eligibility requires RI +6 or above (Regenerative tier),
      combined with overall HIP Score of 9.0 or above.

    ri_descriptors:
      # Labels displayed on the public rating page alongside the RI score.
      # Keyed by [min, max] inclusive range.
      "[-10, -6]": "Depleting"
      "[-5, -1]":  "Extractive"
      "[0, 0]":    "Renewable"
      "[1, 5]":    "Restorative"
      "[6, 10]":   "Regenerative"

    data_sources:
      - name: "Regenerative Organic Certified (ROC)"
        url: "https://regenorganic.org"
        licence: "Public"
        use: >
          The primary certification for verified regenerative agricultural inputs.
          ROC-certified content is the strongest evidence for a positive RI score.

      - name: "FSC / PEFC Forest Certification"
        url: "https://fsc.org and https://pefc.org"
        licence: "Public"
        use: >
          Certified sustainably managed forestry. Scores at or near 0 (Renewable)
          — sustainably managed but not actively regenerative in isolation.

      - name: "Ellen MacArthur Foundation — Circular Economy"
        url: "https://ellenmacarthurfoundation.org"
        licence: "Public (research use)"
        use: >
          Closed-loop manufacturing case studies. Strong closed-loop evidence
          can support a Restorative (+1 to +5) score.

    input_fields:
      - field: "primary_material_origin"
        description: >
          How primary materials are sourced — mined virgin, farmed conventional,
          farmed regenerative/certified, recycled, bio-based, etc.
        required: false
        assumed_default: "mined/extracted (conventional)"
        # Most products have no submitted data for this field.
        # Conservative default: assume conventional extraction.

      - field: "recycled_content_pct"
        description: >
          Percentage of product mass made from post-consumer or post-industrial
          recycled feedstock. Drives Rule 1 (>=50% with take-back → floor at -3)
          and Rule 2 (20-49% → Extractive range) in the v1.3 RI llm_instructions.
        required: false
        assumed_default: 0

      - field: "takeback_scheme"
        description: >
          Boolean — whether the manufacturer operates a verified product take-back
          or recovery scheme. Drives Rule 1 and Rule 2 in the v1.3 RI llm_instructions.
        required: false
        assumed_default: false

      - field: "regenerative_certifications"
        description: >
          Any ROC, FSC, PEFC, B Corp, or equivalent certifications held by the
          manufacturer or their primary material suppliers.
        required: false
        assumed_default: null

      - field: "closed_loop_programme"
        description: >
          Evidence of a manufacturer closed-loop material recovery programme
          (distinct from a simple take-back scheme — this is material-level).
        required: false
        assumed_default: null

      - field: "end_of_life_programme"
        description: >
          Boolean — whether an end-of-life recovery or recycling programme exists
          for the product (broader than take-back; may include council partnerships
          or producer-responsibility schemes).
        required: false
        assumed_default: false

      - field: "material_origin_certified"
        description: >
          Boolean — whether the origin of primary materials is third-party certified
          (e.g. FSC/PEFC for timber, ResponsibleSteel for steel). Supports Rule 4
          (certified materials → Renewable band) in the RI llm_instructions.
        required: false
        assumed_default: false

      - field: "regenerative_practices"
        description: >
          Free-text evidence of regenerative practices in the supply chain
          (supplier partnerships, closed-loop packaging, ecosystem restoration,
          etc.). Null if absent. Supports Rule 5 in the RI llm_instructions.
        required: false
        assumed_default: null

      - field: "third_party_certification"
        description: >
          Name of any third-party certification held (e.g. "ISO 14001:2015",
          "B Corp"). Null if none. Contributes to the Restorative / Regenerative
          band evidence base when combined with material-origin certification.
        required: false
        assumed_default: null

    scoring_rubric:
      # IMPORTANT: RI runs -10 to +10. Negative scores are valid and expected.
      # Do not round negative scores toward zero to soften the result.

      "-10 to -6 (Depleting)":
        label: "Depleting"
        criteria: >
          Dominant materials are non-renewable and actively depleting finite
          geological reserves. No credible pathway toward regeneration.
          No take-back scheme, no recycled content credit from RI perspective.
          Examples: rare earth elements, cobalt, lithium from virgin mine
          extraction with no offset or recovery programme. Standard result
          for most conventional consumer electronics and appliances.

      "-5 to -1 (Extractive)":
        label: "Extractive"
        criteria: >
          Primarily non-renewable but with meaningful mitigating factors —
          substantial recycled content, credible due-diligence on extraction
          practices, or a manufacturer take-back scheme with verified recovery
          rates. Still net-depleting overall but less severely than the floor.

      "0 (Renewable)":
        label: "Renewable"
        criteria: >
          Primary materials are renewable and sourced sustainably.
          Examples: FSC/PEFC-certified timber, certified natural textile fibres.
          Not yet actively building natural capital, but not depleting it.
          This is a meaningful achievement — score it honestly at zero,
          not rounded down or up.

      "+1 to +5 (Restorative)":
        label: "Restorative"
        criteria: >
          Product actively works to reverse existing ecosystem damage — going
          beyond neutral to repair rather than merely sustain. Some certified
          regenerative content (ROC or equivalent), verified ecosystem restoration
          programmes linked to the supply chain, or a closed-loop programme
          demonstrably returning value to natural systems. Partial credit —
          restoration is underway but the product is not yet fully regenerative.

      "+6 to +10 (Regenerative)":
        label: "Regenerative"
        criteria: >
          Primary materials are verified regenerative — ROC-certified agricultural
          inputs, manufacturer demonstrably restoring soil or ecosystem health,
          or fully closed-loop with verified net-positive ecological outcome.
          This range triggers HIP Gold mark eligibility (combined with HIP >= 9.0).
          Evidence must be third-party verified — self-reported claims alone are
          not sufficient to score above +5.

    llm_instructions: |
      You are completing the Regenerative Index (RI) dimension of a Resourcehip
      HIP (Human Impact Profile) sustainability assessment.
      
      CRITICAL: RI runs from -10 to +10. This is NOT a standard 0–10 scale.
      Negative scores are valid, expected, and should be reported honestly.
      Do NOT inflate scores to avoid negatives — that defeats the purpose.
      
      ## SCORING RULES — READ THESE FIRST
      
      Rule 1: Recycled content >= 50% AND take-back scheme present
      → Product qualifies for EXTRACTIVE band minimum of -3. The Depleting floor (-7) 
         does NOT apply. You must cite this explicitly: "Not Depleting because 
         recycled content >= 50% with verified take-back."
      
      Rule 2: Recycled content 20-49% OR take-back scheme present (alone)
      → Product can score in EXTRACTIVE range (-5 to -1).

      Rule 2.5: Primary material origin is 'bio-based renewable'
      → Minimum Extractive band (-5 to -1). The Depleting floor does NOT apply.
         Bio-based renewable materials (plant fibres, wood, natural rubber, cork,
         bamboo) do not deplete finite geological reserves. Without certification,
         they cannot score above Extractive, but they cannot score Depleting.
         Certification (FSC, GOTS, GOLS, ROC, Rainforest Alliance) enables Rule 4
         or Rule 5 uplift toward Renewable (0) or Restorative/Regenerative (+1 to +10).

      Rule 3: No meaningful recycling (<20%) AND no take-back AND not bio-based renewable
      → Default to DEPLETING band, typically -7 for conventional manufactured goods.
      
      Rule 4: FSC/PEFC certified materials
      → Can score at RENEWABLE (0) or near-zero.
      
      Rule 5: Regenerative Organic Certified (ROC) materials
      → Can score POSITIVE (+6 to +10). Self-reported claims cap at +4 maximum.
      
      ## RUBRIC CITATION REQUIREMENT (MANDATORY)
      
      When writing the justification:
      - NAME the band you're applying (Depleting/Extractive/Renewable/Restorative/Regenerative)
      - QUOTE or paraphrase the specific band criteria that apply (e.g., "substantial 
        recycled content AND take-back scheme")
      - EXPLICITLY contrast why the alternative band does NOT apply (e.g., "Not Depleting 
        because...")
      
      ## SANITY-CHECK RANGES (use for verification, not substitution)
      
      - Conventional electronics (no certs): typically -8 to -5
      - Conventional appliances (no certs): typically -7 to -4
      - Partial recycled content: typically -5 to -2
      - FSC/PEFC certified: 0 to +1
      - Verified restorative programmes: +1 to +5
      - ROC-certified regenerative inputs: +6 to +10
      
      ## FINAL RULES
      
      - Use ONLY the product data provided. Do not invent certifications.
      - Scores above 0 require positive submitted evidence.
      - Scores above +5 require third-party verified evidence.
      - Reply in valid JSON only. No prose outside the JSON object.

    output_schema:
      type: object
      required: [ri_raw, ri_descriptor, justification, assumed, assumed_fields]
      properties:
        ri_raw:
          type: number
          minimum: -10
          maximum: 10
          description: >
            Raw RI score to one decimal place. Negative values are expected
            and valid. Example: -5.0 for a conventional appliance.
        ri_descriptor:
          type: string
          enum: ["Depleting", "Extractive", "Renewable", "Restorative", "Regenerative"]
          description: "Label matching the ri_raw score band."
        justification:
          type: string
          maxLength: 300
          description: >
            One to three plain-English sentences explaining the RI score.
            Be specific: name the materials, certifications (or absence of them),
            and any take-back evidence that drove the score.
            This text appears on the public rating page.
        assumed:
          type: boolean
          description: "true if ANY input field was missing and a default was used."
        assumed_fields:
          type: array
          items:
            type: string
          description: >
            Names of fields assumed rather than submitted. Empty array [] if
            all data was provided.


# -----------------------------------------------------------------------------
# CATEGORY BASELINES
# -----------------------------------------------------------------------------
# When a manufacturer has not submitted data for a specific field,
# the pipeline falls back to the category baseline for that product type.
# These baselines are themselves generic ratings — the floor all products
# in that category are compared against.
#
# Format: product_category -> dimension_id -> field_name -> assumed value
# Populated as generic ratings are completed. Start with hair dryer (first case).

category_baselines:

  hair_dryer:
    # Source: generic category knowledge — update as verified submissions arrive.
    # This baseline represents a typical mass-market corded hair dryer.
    MSI:
      primary_materials:
        - "copper"           # motor windings, wiring
        - "nichrome"         # heating element
        - "ABS plastic"      # housing
        - "stainless steel"  # grille, some internal components
      recycled_content_pct: 5
      # Note: some premium models claim higher recycled ABS — default is conservative.
    SCR:
      primary_sourcing_countries: ["China", "Chile", "DRC"]
      tier1_supplier_count: 1
      due_diligence_standard: null
      alternative_supplier_exists: false
      # Expected SCR: 3-4 (copper and nichrome have real concentration risk; alternatives exist in principle)
    RC:
      disassembly_type: "mixed_screws_clips"
      recyclable_streams_pct: 25
      recycling_label_compliant: false
      takeback_scheme: false
      design_for_disassembly: false
      # Expected RC: 3-4 (copper wiring recovered; ABS and nichrome largely landfilled)
    R:
      fastener_type: "mixed_screws_clips"
      spare_parts_available: false
      spare_parts_years_committed: 0
      service_manual_public: false
      ifixit_score: null
      ecodesign_in_scope: false
      # Expected R: 2-4 (mass-market hair dryers designed as disposables; some screws but no parts programme)
    SEI:
      manufacturing_countries: ["China"]
      environmental_certifications: []
      rba_audit_completed: false
      modern_slavery_statement: false
      ilo_compliance_claimed: false
      # Expected SEI: 3-5 (manufacturing in China with no certifications; moderate assumed risk)
    PL:
      warranty_years: 1
      stated_design_life_years: null
      ip_rating: null
      modular_design: false
      software_support_years: null
      # Expected PL: 3-5 (typical 1-2 year warranty, 5-7 year real-world life, no IP rating)
    RI:
      primary_material_origin: "mined/extracted (conventional)"
      regenerative_certifications: null
      closed_loop_programme: null
      # Expected RI for a conventional hair dryer: approximately -6.0 (Depleting)

  cork_products:
    # Source: generic category knowledge — update as verified submissions arrive.
    # Represents a typical mass-market cork product (trivet, coaster, board, stopper, bag).
    # Cork bark is harvested non-destructively from living Quercus suber trees every 9–12 years.
    MSI:
      primary_materials:
        - "cork"                  # bark of Quercus suber (non-destructive harvest)
        - "natural binder"        # small amount in agglomerated cork products
      recycled_content_pct: 0
      # Expected MSI: 8–9 (bio-based, abundant, no EU CRM-listed materials)
    SCR:
      primary_sourcing_countries: ["Portugal", "Spain", "Morocco"]
      tier1_supplier_count: 2
      due_diligence_standard: null
      alternative_supplier_exists: true
      # Expected SCR: 5–7 (Portugal ~50% global supply but stable EU governance;
      # Spain and Morocco provide meaningful diversification)
    RC:
      disassembly_type: "mixed_screws_clips"
      recyclable_streams_pct: 15
      recycling_label_compliant: false
      takeback_scheme: false
      design_for_disassembly: false
      # Expected RC: 2–4 (cork is compostable/biodegradable but industrial composting
      # required; not accepted by kerbside collections in most UK local authorities)
    R:
      fastener_type: "mixed_screws_clips"
      spare_parts_available: false
      spare_parts_years_committed: 0
      service_manual_public: false
      ifixit_score: null
      ecodesign_in_scope: false
      # Expected R: 2–4 (simple products; no formal repair programme; DIY repair feasible)
    SEI:
      manufacturing_countries: ["Portugal", "Spain", "China"]
      environmental_certifications: []
      rba_audit_completed: false
      modern_slavery_statement: false
      ilo_compliance_claimed: false
      # Expected SEI: 4–6 (European manufacturing common; good baseline labour standards
      # in Portugal/Spain; some Chinese finishing assumed conservative default)
    PL:
      warranty_years: 1
      stated_design_life_years: null
      ip_rating: null
      modular_design: false
      software_support_years: null
      # Expected PL: 4–6 (cork is naturally durable; trivets/coasters last many years
      # with basic care; modest warranty typical)
    RI:
      primary_material_origin: "bio-based renewable"
      regenerative_certifications: null
      closed_loop_programme: null
      # Expected RI: approximately -1 to +2 (bio-based renewable; cork harvest is
      # non-destructive and bark regenerates every 9–12 years; no organic cert assumed
      # by default — cert uplift to Restorative applies when confirmed)

  bamboo_kitchenware:
    # Source: generic category knowledge — update as verified submissions arrive.
    # Represents a typical bamboo kitchenware item (cutting board, utensil, serving tray).
    # Bamboo is a rapidly renewable grass; typical growth cycle is 3–5 years.
    MSI:
      primary_materials:
        - "bamboo"                  # rapidly renewable grass (Bambusoideae)
        - "food-grade adhesive"     # used in laminated/compressed bamboo boards
      recycled_content_pct: 0
      # Expected MSI: 8–9 (bio-based, abundant; adhesive binders are minor by weight)
    SCR:
      primary_sourcing_countries: ["China", "Vietnam"]
      tier1_supplier_count: 1
      due_diligence_standard: null
      alternative_supplier_exists: false
      # Expected SCR: 3–5 (China-dominant supply; moderate geopolitical concentration)
    RC:
      disassembly_type: "glued"
      recyclable_streams_pct: 10
      recycling_label_compliant: false
      takeback_scheme: false
      design_for_disassembly: false
      # Expected RC: 1–3 (laminated bamboo with adhesive binders is not compostable
      # in practice; no kerbside recycling stream for bamboo kitchenware in UK)
    R:
      fastener_type: "glued"
      spare_parts_available: false
      spare_parts_years_committed: 0
      service_manual_public: false
      ifixit_score: null
      ecodesign_in_scope: false
      # Expected R: 1–2 (kitchenware not designed for repair; bonded construction)
    SEI:
      manufacturing_countries: ["China"]
      environmental_certifications: []
      rba_audit_completed: false
      modern_slavery_statement: false
      ilo_compliance_claimed: false
      # Expected SEI: 3–5 (China manufacturing with no certifications assumed)
    PL:
      warranty_years: 1
      stated_design_life_years: null
      ip_rating: null
      modular_design: false
      software_support_years: null
      # Expected PL: 3–5 (durable with care; minimal warranty typical)
    RI:
      primary_material_origin: "bio-based renewable"
      regenerative_certifications: null
      closed_loop_programme: null
      # Expected RI: approximately -1 to +1 (bio-based renewable; bamboo is rapidly
      # renewable but conventional Chinese farming assumed; no organic cert by default)

  linen_hemp_accessories:
    # Source: generic category knowledge — update as verified submissions arrive.
    # Represents a typical linen or hemp textile accessory (bag, tote, homewares, belt).
    # Flax (linen) and hemp are annual crops documented to improve soil health.
    MSI:
      primary_materials:
        - "linen (flax fibre)"    # Linum usitatissimum; soil-improving annual crop
        - "hemp fibre"            # Cannabis sativa; soil-improving annual crop
        - "natural thread"
      recycled_content_pct: 5
      # Expected MSI: 8–9 (bio-based natural fibres; no EU CRM-listed materials)
    SCR:
      primary_sourcing_countries: ["France", "Belgium", "China"]
      tier1_supplier_count: 2
      due_diligence_standard: null
      alternative_supplier_exists: true
      # Expected SCR: 5–7 (multiple growing regions; European production stable;
      # Chinese hemp supply adds diversification)
    RC:
      disassembly_type: "clips_only"
      recyclable_streams_pct: 15
      recycling_label_compliant: false
      takeback_scheme: false
      design_for_disassembly: false
      # Expected RC: 2–4 (natural fibres compostable in principle; textile-to-textile
      # recycling infrastructure limited in UK practice; synthetic dyes or metal
      # hardware complicate end-of-life streams)
    R:
      fastener_type: "clips_only"
      spare_parts_available: false
      spare_parts_years_committed: 0
      service_manual_public: false
      ifixit_score: null
      ecodesign_in_scope: false
      # Expected R: 2–4 (home textile repair is feasible; no formal parts programme)
    SEI:
      manufacturing_countries: ["China", "France"]
      environmental_certifications: []
      rba_audit_completed: false
      modern_slavery_statement: false
      ilo_compliance_claimed: false
      # Expected SEI: 4–5 (mixed manufacturing; European production has strong labour
      # standards; Chinese production moderate risk without certifications)
    PL:
      warranty_years: 1
      stated_design_life_years: null
      ip_rating: null
      modular_design: false
      software_support_years: null
      # Expected PL: 4–6 (quality linen/hemp is inherently durable; can last 10+ years
      # with care; modest warranty typical)
    RI:
      primary_material_origin: "bio-based renewable"
      regenerative_certifications: null
      closed_loop_programme: null
      # Expected RI: approximately 0 to +2 (bio-based renewable; flax and hemp are
      # documented soil-improving crops; no organic cert assumed by default — GOTS or
      # organic cert would lift score toward Restorative band)

  wooden_toys_games:
    # Source: generic category knowledge — update as verified submissions arrive.
    # Represents a typical solid-wood toy or game (blocks, puzzles, board games).
    # FSC certification is prevalent at mainstream retail but NOT assumed by default —
    # applies cert uplift only when manufacturer confirms FSC/PEFC status.
    MSI:
      primary_materials:
        - "solid wood (softwood/hardwood)"  # e.g. beech, pine, maple
        - "water-based paint or varnish"
        - "metal hardware"                  # small amount; screws, hinges
      recycled_content_pct: 0
      # Expected MSI: 8–9 (wood is abundant; no EU CRM-listed materials; minor metal hardware)
    SCR:
      primary_sourcing_countries: ["Germany", "Poland", "China"]
      tier1_supplier_count: 2
      due_diligence_standard: null
      alternative_supplier_exists: true
      # Expected SCR: 5–7 (many global forest regions; EU producers stable;
      # multiple viable sourcing options reduce concentration risk)
    RC:
      disassembly_type: "standard_screws"
      recyclable_streams_pct: 30
      recycling_label_compliant: false
      takeback_scheme: false
      design_for_disassembly: false
      # Expected RC: 3–5 (solid wood is biodegradable; metal hardware recoverable;
      # paint/varnish may complicate composting but practical streams better than
      # synthetic products)
    R:
      fastener_type: "standard_screws"
      spare_parts_available: false
      spare_parts_years_committed: 0
      service_manual_public: false
      ifixit_score: null
      ecodesign_in_scope: false
      # Expected R: 4–6 (simple construction; DIY repair highly feasible; wooden toys
      # are among the most repairable consumer product categories; no formal programme)
    SEI:
      manufacturing_countries: ["Germany", "China"]
      environmental_certifications: []
      rba_audit_completed: false
      modern_slavery_statement: false
      ilo_compliance_claimed: false
      # Expected SEI: 4–6 (mixed EU/China manufacturing; EU production has strong
      # labour protections; Chinese toy manufacturing moderate risk without certs)
    PL:
      warranty_years: 1
      stated_design_life_years: null
      ip_rating: null
      modular_design: false
      software_support_years: null
      # Expected PL: 5–7 (solid wood is inherently durable; well-made wooden toys
      # can last generations; actual lifespan substantially exceeds typical warranty)
    RI:
      primary_material_origin: "bio-based renewable"
      regenerative_certifications: null
      closed_loop_programme: null
      # Expected RI: approximately -1 to +1 (bio-based renewable; FSC certification
      # common at mainstream retail but not assumed here — confirmed FSC/PEFC lifts
      # score to Renewable band 0 or near-zero)

  natural_latex_sleep:
    # Source: generic category knowledge — update as verified submissions arrive.
    # Represents a typical natural latex mattress, pillow, or topper.
    # GOLS (Global Organic Latex Standard) certification is prevalent in this category
    # and is reflected in the RI baseline to enable cert uplift.
    MSI:
      primary_materials:
        - "natural latex (Hevea brasiliensis)"  # tapped from rubber trees non-destructively
        - "organic cotton (cover)"
        - "natural wool (fire-retardant layer)"
      recycled_content_pct: 0
      # Expected MSI: 7–9 (bio-based natural materials; rubber tree tapping non-destructive)
    SCR:
      primary_sourcing_countries: ["Thailand", "Indonesia", "Malaysia"]
      tier1_supplier_count: 2
      due_diligence_standard: null
      alternative_supplier_exists: true
      # Expected SCR: 4–6 (SE Asian supply concentration; multiple producing countries;
      # stable governance compared to conflict-mineral categories)
    RC:
      disassembly_type: "clips_only"
      recyclable_streams_pct: 15
      recycling_label_compliant: false
      takeback_scheme: false
      design_for_disassembly: false
      # Expected RC: 2–4 (natural latex is biodegradable; however, mattress recycling
      # infrastructure is very limited in UK practice; covers removable and washable)
    R:
      fastener_type: "clips_only"
      spare_parts_available: false
      spare_parts_years_committed: 0
      service_manual_public: false
      ifixit_score: null
      ecodesign_in_scope: false
      # Expected R: 2–4 (covers removable and washable; latex core not repairable;
      # no spare parts programme in mainstream market)
    SEI:
      manufacturing_countries: ["Thailand", "Indonesia"]
      environmental_certifications: []
      rba_audit_completed: false
      modern_slavery_statement: false
      ilo_compliance_claimed: false
      # Expected SEI: 4–6 (SE Asian manufacturing; GOLS includes social and environmental
      # standards but not universally applied at factory level — use this as a floor)
    PL:
      warranty_years: 2
      stated_design_life_years: null
      ip_rating: null
      modular_design: false
      software_support_years: null
      # Expected PL: 6–8 (natural latex is inherently long-lasting; 15–25 year design
      # life typical; many GOLS products carry 10-year+ warranties but conservative
      # 2-year default used here pending manufacturer submission)
    RI:
      primary_material_origin: "bio-based renewable"
      regenerative_certifications: "GOLS"
      closed_loop_programme: null
      # Expected RI: approximately +1 to +4 (GOLS-certified organic latex; rubber tree
      # tapping is non-destructive and restorative; third-party cert supports Restorative
      # band — scores above +5 require additional verified regenerative practice evidence)

  # PHASE_5_SCOPE_CHECK_REQUIRED — do not use for live ratings until Phase 5 confirms
  # that HIP methodology dimensions RC, R, and PL are applicable to consumable products.
  # This baseline entry is added to the library but blocked from live scoring runs.
  # CEO sign-off condition documented in RES-57 (2026-04-27). Unblock only after RES
  # Phase 5 scope review explicitly clears this category.
  solid_personal_care_bars:
    # Source: generic category knowledge — update as verified submissions arrive.
    # Represents a typical solid personal care bar (shampoo, soap, conditioner, lotion).
    # WARNING: Consumable product — RC, R, and PL dimensions require Phase 5 scope review.
    # PHASE_5_SCOPE_CHECK_REQUIRED before any rating in this category goes live.
    MSI:
      primary_materials:
        - "plant-based surfactants (e.g. sodium cocoyl isethionate)"
        - "plant oils and butters (e.g. shea, coconut, castor)"
        - "botanicals and essential oils"
      recycled_content_pct: 0
      # Expected MSI: 7–9 (plant-based renewable ingredients; palm oil may attract
      # deforestation flags — RSPO certification would improve score)
    SCR:
      primary_sourcing_countries: ["Malaysia", "Indonesia", "UK", "France"]
      tier1_supplier_count: 2
      due_diligence_standard: null
      alternative_supplier_exists: true
      # Expected SCR: 4–6 (palm oil from SE Asia has concentration risk;
      # most other ingredients have multiple sourcing options)
    RC:
      disassembly_type: "clips_only"
      recyclable_streams_pct: 5
      recycling_label_compliant: false
      takeback_scheme: false
      design_for_disassembly: false
      # SCOPE NOTE: Product is consumed in use — RC metrics apply to packaging only,
      # not the product itself. recyclable_streams_pct here reflects packaging waste.
      # PHASE_5_SCOPE_CHECK_REQUIRED before scoring this dimension for live ratings.
      # Expected RC: N/A (consumable); minimal packaging typically paper/card — 5–7
    R:
      fastener_type: "clips_only"
      spare_parts_available: false
      spare_parts_years_committed: 0
      service_manual_public: false
      ifixit_score: null
      ecodesign_in_scope: false
      # SCOPE NOTE: Repairability is not applicable to consumable products.
      # PHASE_5_SCOPE_CHECK_REQUIRED before scoring this dimension for live ratings.
      # Expected R: N/A (consumable product)
    SEI:
      manufacturing_countries: ["UK", "France", "China"]
      environmental_certifications: []
      rba_audit_completed: false
      modern_slavery_statement: false
      ilo_compliance_claimed: false
      # Expected SEI: 4–6 (mixed manufacturing; UK/EU production common in this
      # category with good baseline labour standards)
    PL:
      warranty_years: 1
      stated_design_life_years: null
      ip_rating: null
      modular_design: false
      software_support_years: null
      # SCOPE NOTE: Product Longevity is not directly applicable to consumable products
      # (lifespan determined by use rate, not product design life).
      # PHASE_5_SCOPE_CHECK_REQUIRED before scoring this dimension for live ratings.
      # Expected PL: N/A (consumable product)
    RI:
      primary_material_origin: "bio-based renewable"
      regenerative_certifications: null
      closed_loop_programme: null
      # Expected RI: approximately 0 to +2 (bio-based renewable plant ingredients;
      # conventional sourcing assumed; RSPO palm oil cert or organic cert would
      # improve score toward Restorative band)

  natural_fill_duvets_pillows:
    # Source: generic category knowledge — created per RES-1094 decision C / RES-1096.
    # Represents a typical natural-fill duvet or pillow carrying GOTS certification
    # (organic fibre outer ticking) and RDS (Responsible Down Standard) for down/feather fill.
    # See pipeline/inputs/duvets-pillows-natural-fill-generic.json for the input file.
    # Contrast with the synthetic-fill baseline which uses Depleting RI defaults.
    MSI:
      primary_materials:
        - "duck or goose down/feather fill"      # animal by-product; bio-based
        - "wool fill (where applicable)"          # animal by-product; bio-based
        - "GOTS-certified organic cotton (ticking)" # bio-based renewable
      recycled_content_pct: 0
      # Expected MSI: 7–9 (bio-based natural materials; no EU CRM-listed materials;
      # down and wool are abundant; supply concentration risk is in supply chain, not scarcity)
    SCR:
      primary_sourcing_countries: ["Hungary", "Poland", "China", "India", "Turkey"]
      tier1_supplier_count: 2
      due_diligence_standard: null
      alternative_supplier_exists: true
      # Expected SCR: 4–6 (Hungary/Poland dominate EU premium down; China dominates global
      # volume; multiple sourcing countries reduce single-source exposure; GOTS/RDS provide
      # chain-of-custody traceability but not a formal OECD/RBA due-diligence programme)
    RC:
      disassembly_type: "clips_only"
      recyclable_streams_pct: 10
      recycling_label_compliant: false
      takeback_scheme: false
      design_for_disassembly: false
      # Expected RC: 2–4 (natural fill is biodegradable but not practically recyclable
      # via UK kerbside; organic cotton ticking compostable in principle; no mainstream
      # textile take-back scheme for bedding; cotton and down streams not routinely recovered)
    R:
      fastener_type: "clips_only"
      spare_parts_available: false
      spare_parts_years_committed: 0
      service_manual_public: false
      ifixit_score: null
      ecodesign_in_scope: false
      # Expected R: 3–5 (hand-sewn seams are DIY-repairable; re-stuffing feasible;
      # no formal spare parts programme; simpler to repair than synthetic alternatives)
    SEI:
      manufacturing_countries: ["Poland", "China"]
      environmental_certifications: ["GOTS", "RDS"]
      rba_audit_completed: false
      modern_slavery_statement: false
      ilo_compliance_claimed: true
      # Expected SEI: 5–7 (GOTS certification covers ILO core labour standards and
      # restricted substances; RDS covers animal welfare chain-of-custody; third-party
      # cert provides meaningful uplift over uncertified Asian-manufactured bedding)
    PL:
      warranty_years: 2
      stated_design_life_years: 10
      ip_rating: null
      modular_design: false
      software_support_years: null
      # Expected PL: 5–7 (quality natural-fill bedding lasts 10–15 years with proper care;
      # significantly longer than synthetic-fill equivalents; modest warranty assumed;
      # correct tog and fill-power specification drives longevity)
    RI:
      primary_material_origin: "bio-based renewable"
      regenerative_certifications: "GOTS"
      closed_loop_programme: null
      # Expected RI: approximately -3 to 0
      # Rule 2.5 applies: bio-based renewable materials — Depleting floor (-6) does NOT apply.
      # GOTS certification (Rule 4): enables uplift toward Renewable (0); organic fibre
      # cultivation includes soil health and no synthetic pesticides.
      # No ROC certification assumed — capped below Restorative without additional evidence.
      # Scores above 0 require verified regenerative agricultural practices (e.g. ROC-cert).
      # Animal welfare (down/wool): bio-based, not geological extraction — Extractive band
      # applies honestly; RDS ensures welfare standards but does not make fill regenerative.


# -----------------------------------------------------------------------------
# CATEGORY TYPE MAPPING  (v1.4)
# -----------------------------------------------------------------------------
# Deterministic lookup from input product_type (free-text) → category_weight_profile.
# Pipeline lookup:
#   profile_key = category_type_mapping.get(
#     product_data.product_type.strip().lower(),
#     None  # None = fall back to base dimension weights
#   )
# Unmapped product_types fall back to base weights — no error, no warning.
# Keys are matched case-insensitively after trim.

category_type_mapping:

  # buy_it_for_life_durables
  "cast iron cookware": "buy_it_for_life_durables"
  "carbon steel pan": "buy_it_for_life_durables"
  "carbon steel wok": "buy_it_for_life_durables"
  "hand tool": "buy_it_for_life_durables"
  "kitchen knife": "buy_it_for_life_durables"
  "solid brass fitting": "buy_it_for_life_durables"

  # consumables_razor_blade (the durable device half)
  "coffee pod machine": "consumables_razor_blade"
  "razor handle": "consumables_razor_blade"
  "water filter jug": "consumables_razor_blade"
  "candle holder": "consumables_razor_blade"

  # consumable_unit (the consumable half — see system_boundary_rules)
  "coffee pod": "consumable_unit"
  "razor blade cartridge": "consumable_unit"
  "water filter cartridge": "consumable_unit"
  "candle": "consumable_unit"
  "ink cartridge": "consumable_unit"

  # safety_sealed
  "smoke alarm": "safety_sealed"
  "carbon monoxide detector": "safety_sealed"
  "electric toothbrush": "safety_sealed"
  "blood pressure monitor": "safety_sealed"

  # software_dependent_electronics
  "robot vacuum cleaner": "software_dependent_electronics"
  "smart speaker": "software_dependent_electronics"
  "smart home hub": "software_dependent_electronics"
  "connected oven": "software_dependent_electronics"

  # battery_bearing_electronics
  "wireless earbuds": "battery_bearing_electronics"
  "wireless headphones": "battery_bearing_electronics"
  "bluetooth headphones": "battery_bearing_electronics"
  "portable bluetooth speaker": "battery_bearing_electronics"
  "portable speaker": "battery_bearing_electronics"
  "electric shaver": "battery_bearing_electronics"
  "cordless drill": "battery_bearing_electronics"
  "smartphone": "battery_bearing_electronics"

  # single_use_packaging
  "cardboard box": "single_use_packaging"
  "paper carrier bag": "single_use_packaging"
  "polythene mailing bag": "single_use_packaging"
  "compostable food container": "single_use_packaging"
  "cellulose film": "single_use_packaging"


# -----------------------------------------------------------------------------
# CATEGORY WEIGHT PROFILES  (v1.4)
# -----------------------------------------------------------------------------
# Per-product-type dimensional weight overrides.
# Pipeline lookup: profile_key from category_type_mapping → this map.
# All profiles must sum to exactly 1.0 (validated at load time).
# N/A dimensions are listed in na_dimensions[]; their weights are pre-zeroed.
# Runtime gate N/As (e.g. safety_sealed gate) are handled by
# na_renormalisation_rules.

category_weight_profiles:

  buy_it_for_life_durables:
    examples:
      - "cast iron cookware (Le Creuset, Lodge, Netherton Foundry)"
      - "carbon steel pans (de Buyer)"
      - "hand tools (hammers, chisels, planes)"
      - "quality kitchen knives (full-tang)"
    rationale: >
      Repairability and longevity are the BIFL claim. RC is less relevant —
      a well-maintained BIFL product should never reach end-of-life during
      its owner's lifetime. RI reduced because long product life amortises
      extraction impact.
    weights:
      MSI: 0.17
      SCR: 0.14
      RC:  0.09
      R:   0.25
      SEI: 0.08
      PL:  0.22
      RI:  0.05
    na_dimensions: []

  consumables_razor_blade:
    examples:
      - "coffee pod machines (Nespresso, Dolce Gusto)"
      - "razor handles (Gillette, Wilkinson)"
      - "candle holders"
      - "water filter jugs (Brita, LifeStraw)"
    rationale: >
      RC rises sharply because the consumable packaging stream is the dominant
      waste vector. RI rises because renewable consumable inputs are the key
      sustainability lever. R and PL fall because device durability is less
      differentiating than the consumable system sustainability.
    weights:
      MSI: 0.16
      SCR: 0.13
      RC:  0.28
      R:   0.06
      SEI: 0.08
      PL:  0.07
      RI:  0.22
    na_dimensions: []

  consumable_unit:
    examples:
      - "Nespresso / Dolce Gusto pods"
      - "razor blade cartridges"
      - "single candles"
      - "water filter cartridges"
    rationale: >
      Single-use scoring. Packaging recyclability is dominant; material origin
      (bio-based vs fossil) is the second-largest lever. R and PL are N/A
      because the concepts don't apply.
    weights:
      MSI: 0.20
      SCR: 0.15
      RC:  0.35
      R:   0.00
      SEI: 0.10
      PL:  0.00
      RI:  0.20
    na_dimensions: ["R", "PL"]

  safety_sealed:
    examples:
      - "smoke alarms (Kidde, Aico, FireAngel)"
      - "carbon monoxide detectors"
      - "electric toothbrush handles (Oral-B, Sonicare)"
      - "sealed blood pressure monitors"
    rationale: >
      MSI and SCR rise because sensor and battery materials warrant higher
      scrutiny. R pre-zeroed via safety_sealed gate (regulatory mandate, not
      design failure). PL rises because device replacement cadence is the
      primary sustainability concern in safety devices.
    weights:
      MSI: 0.22
      SCR: 0.20
      RC:  0.13
      R:   0.00
      SEI: 0.10
      PL:  0.20
      RI:  0.15
    na_dimensions: ["R"]

  software_dependent_electronics:
    examples:
      - "robot vacuums (Roomba, Roborock, Dyson 360)"
      - "smart speakers (Amazon Echo, Google Nest)"
      - "smart home hubs"
      - "connected kitchen appliances"
    rationale: >
      PL rises significantly — software support horizon is the actual useful
      life determinant. R rises slightly because hardware modularity can
      extend post-support life. RI falls because short-software-life products
      amortise poorly.
    weights:
      MSI: 0.18
      SCR: 0.15
      RC:  0.14
      R:   0.16
      SEI: 0.08
      PL:  0.20
      RI:  0.09
    na_dimensions: []

  battery_bearing_electronics:
    examples:
      - "wireless earbuds (AirPods, Sony WF, Jabra)"
      - "over-ear wireless headphones (Sony WH, Bose QC)"
      - "portable Bluetooth speakers (JBL, Ultimate Ears)"
      - "handheld electric shavers (Philips, Braun)"
    rationale: >
      MSI/SCR rise significantly — cobalt, lithium, and REE magnets are the
      dominant material concerns. R rises — battery replaceability is the
      single most impactful repairability criterion. RI falls because these
      products are predominantly mining-dependent.
    weights:
      MSI: 0.26
      SCR: 0.22
      RC:  0.18
      R:   0.18
      SEI: 0.07
      PL:  0.08
      RI:  0.01
    na_dimensions: []

  single_use_packaging:
    scope_note: >
      PHASE 1 SCOPE (approved by CEO 2026-06-14, RES-1207): single-use packaging
      is rated and scored when submitted (v1.4 profiles are complete), but packaging
      ratings are NOT published as standalone searchable products on resourcehip.com.
      Instead, packaging RC and RI scores are visible embedded in parent product
      ratings (e.g. kettle rating displays "Packaging: RC 7.2 | RI +1"). This approach
      maintains focus on primary consumer products during soft launch. Packaging-as-primary
      products deferred to Phase 2 expansion (subject to demand validation and business
      model confirmation). See RES-1207 decision log for full rationale.
    examples:
      - "cardboard shipping boxes"
      - "paper carrier bags"
      - "polythene mailing bags"
      - "compostable food containers"
      - "cellulose (cellophane) film"
    rationale: >
      RC is dominant — recyclability at scale is the primary concern. RI rises
      because bio-based or recycled origin vs virgin fossil is the key material
      choice. R and PL N/A — concepts don't apply to single-use.
    weights:
      MSI: 0.12
      SCR: 0.10
      RC:  0.38
      R:   0.00
      SEI: 0.08
      PL:  0.00
      RI:  0.32
    na_dimensions: ["R", "PL"]


# -----------------------------------------------------------------------------
# N/A RENORMALISATION RULES  (v1.4)
# -----------------------------------------------------------------------------
# When one or more dimensions is marked N/A for a product, their weight is
# redistributed proportionally among the remaining scored dimensions.
# Deterministic — no LLM judgment.
#
# Formula:
#   na_weight_total = sum(weight[d] for d in active_na_dimensions)
#   for each scored dimension d:
#     effective_weight[d] = declared_weight[d] / (1.0 - na_weight_total)
#
# active_na_dimensions = profile.na_dimensions ∪ runtime_gate_na_dimensions
#
# Rounding: effective weights rounded to 4 decimal places.
# Validation: sum(effective_weights) == 1.0 ± 0.001.

na_renormalisation_rules:
  formula: "effective_weight[d] = declared_weight[d] / (1.0 - sum(weight[d] for d in active_na_dimensions))"
  rounding_precision: 4
  validation_tolerance: 0.001
  na_criteria:
    R:
      - trigger: "product_data.safety_sealed == true"
        reason: >
          Safety-mandated sealing is a regulatory requirement (EN 14604,
          IEC 60335, BS EN 62133), not a design failure. R is N/A and its
          weight redistributes.
      - trigger: "profile.na_dimensions contains 'R'"
        reason: >
          consumable_unit and single_use_packaging profiles pre-declare R=N/A
          because repairability is not a meaningful concept for single-use items.
    PL:
      - trigger: "profile.na_dimensions contains 'PL'"
        reason: >
          consumable_unit and single_use_packaging profiles pre-declare PL=N/A
          because product longevity is not applicable to single-use items.


# -----------------------------------------------------------------------------
# SYSTEM-BOUNDARY RULES  (v1.4)
# -----------------------------------------------------------------------------
# For products whose sustainability depends on an ongoing consumable stream,
# the system boundary must be explicitly declared before scoring begins.

system_boundary_rules:
  consumable_stream:
    default_approach: "score_device_and_consumable_separately"
    # Option A: rate.py generates two HIP ratings — device (consumables_razor_blade
    # profile) and consumable unit (consumable_unit profile). Both published.
    fallback: "mark_out_of_scope_with_ceo_sign_off"
    # Option B: product_data.consumable_stream_status = "out_of_scope".
    # Scope note on public page. Requires CEO sign-off — set
    # product_data.consumable_oos_approval_ref to the issue id with CEO approval.
    scoring_unit: "single_representative_consumable_unit"
    # Score one typical unit (one pod, one cartridge), not lifetime aggregate.
    version_independence: true
    # Device and consumable ratings are independently versioned.


# -----------------------------------------------------------------------------
# GATING FACTORS  (v1.4)
# -----------------------------------------------------------------------------
# Pre-score checks evaluated BEFORE the LLM dimension-scoring step.
# Deterministic — never LLM-inferred.

gating_factors:

  software_eol:
    trigger_conditions:
      - "product_data.is_software_dependent == true"
      - "product_data.software_support_years is not null"
      - "product_data.software_support_years < 2"
    effect:
      dimension: PL
      action: score_cap
      cap_value: 3
    mandatory_flag: >
      Software support < 2 years from launch — physical longevity is irrelevant
      after software EOL; PL capped at 3.
    note: >
      If software_support_years is null and is_software_dependent is true, the
      gate does NOT trigger (benefit of the doubt). The PL rubric's null-handling
      then drives the conservative score.

  safety_sealed:
    trigger_conditions:
      - "product_data.safety_sealed == true"
    effect:
      dimension: R
      action: mark_na
    mandatory_flag: >
      Safety-sealed construction — repairability dimension not applicable.
      Sealing mandated by safety regulation.
    note: >
      Triggered ONLY by explicit product_data.safety_sealed == true. Never
      LLM-inferred from product description. If product_data.safety_standard
      is set, include the standard name in the flag text.

  battery_non_replaceable:
    trigger_conditions:
      - "product_data.battery_replaceable == false"
      - "product_data.battery_chemistry != 'none'"
      - "product_data.battery_chemistry is not null"
    effect:
      dimension: R
      action: flag
    mandatory_flag: >
      Non-replaceable battery — primary driver of premature product obsolescence
      regardless of category. Battery replacement would extend useful life
      significantly.
    note: >
      Applies to any product carrying a battery chemistry other than 'none'
      where the user cannot replace the battery. Catches electric toothbrushes,
      robot vacuums, earbuds uniformly.


# -----------------------------------------------------------------------------
# COMPOSITION SCHEMA  (v1.4)
# -----------------------------------------------------------------------------
# Declared composition fields for battery chemistry, declared materials,
# and per-category published-default fallbacks.
#
# CRITICAL RULES:
#   1. No LLM inference on composition. If a composition field is not submitted,
#      the pipeline uses the published category default. The LLM is told which
#      fields were declared vs defaulted.
#   2. No post-LLM score adjustments. Battery chemistry context shapes the
#      LLM's anchor via llm_instructions text only. The pipeline never
#      numerically modifies dimension scores after the LLM returns them.

composition_schema:

  battery_chemistry:
    description: >
      Declared battery chemistry. Drives LLM scoring of MSI and SCR via prompt
      anchor text (NOT via post-score numerical modifier). Must be declared;
      never inferred.
    field: "product_data.battery_chemistry"
    accepted_values:
      - "Li-ion (NMC)"
      - "Li-ion (LFP)"
      - "Li-ion (NCA)"
      - "Li-ion (unspecified)"
      - "NiMH"
      - "NiCd"
      - "alkaline"
      - "none"
    category_defaults:
      battery_bearing_electronics: "Li-ion (unspecified)"
      safety_sealed: "Li-ion (unspecified)"
      software_dependent_electronics: "Li-ion (unspecified)"

    llm_anchor_guidance:
      "Li-ion (NMC)": >
        Battery chemistry is Li-ion NMC — contains cobalt and nickel, both
        EU Critical Raw Materials. Anchor MSI 1-2 points lower than the
        category baseline; anchor SCR 1-2 points lower due to DRC cobalt
        concentration risk.
      "Li-ion (LFP)": >
        Battery chemistry is Li-ion LFP — cobalt-free, primary materials are
        iron and phosphate (both abundant). Anchor MSI ~1 point HIGHER than
        the NMC baseline; SCR similar uplift.
      "Li-ion (NCA)": >
        Battery chemistry is Li-ion NCA — contains cobalt, nickel, aluminium.
        Anchor MSI/SCR 1-2 points lower (similar to NMC).
      "Li-ion (unspecified)": >
        Battery chemistry not declared. Assume worst-case NMC anchor: 1-2
        points lower on MSI/SCR than a battery-free baseline.
      "NiMH": >
        NiMH chemistry — nickel supply concentration risk but no cobalt.
        Anchor MSI/SCR ~0.5 points lower than baseline.
      "NiCd": >
        NiCd chemistry — cadmium is EU CRM-listed and toxic. Anchor MSI 2+
        points lower than baseline; SCR similarly impacted.
      "alkaline": >
        Disposable alkaline (zinc-manganese) — abundant materials but single-use
        waste stream. Anchor MSI roughly neutral; flag the disposable nature on
        RC dimension.
      "none": >
        No battery present. No chemistry-related MSI/SCR adjustment.

  declared_materials:
    description: >
      Primary materials with declared percentages and certifications.
      New format preferred but coexists with legacy three-field format.
    field: "product_data.declared_materials"
    format:
      - material_name: string
        percentage_by_weight: number | null
        certification: string | null
        origin_country: string | null
    legacy_format_compatibility:
      pipeline_resolution_order:
        1: "If product_data.declared_materials is present and non-empty, use it."
        2: "Otherwise, fall back to legacy: primary_materials, material_percentages, country_of_primary_extraction."
        3: "If neither submitted, use category_baselines[category_type].MSI.primary_materials."
      migration_policy: >
        Existing ceiling input files are NOT required to migrate to
        declared_materials before v1.4 ships. Legacy format remains
        supported indefinitely.

  declared_consumable_ingredients:
    description: >
      Primary ingredients/materials of the consumable itself. Drives RC,
      MSI, and RI for consumable_unit ratings. Never inferred.
    field: "product_data.consumable_ingredients"
    required_for: ["consumable_unit", "consumables_razor_blade"]
    format:
      - ingredient_name: string
        percentage_by_weight: number | null
        bio_based: boolean | null
        certification: string | null

  category_defaults:
    buy_it_for_life_durables:
      primary_materials: ["cast iron", "carbon steel", "enamel coating"]
      battery_chemistry: "none"
    consumables_razor_blade:
      primary_materials: ["ABS plastic", "stainless steel", "elastomer grip"]
      battery_chemistry: "none"
    consumable_unit:
      primary_materials_by_subtype:
        coffee_pod: ["aluminium", "coffee grounds", "polypropylene lid"]
        razor_blade_cartridge: ["stainless steel", "PTFE coating", "plastic cartridge body"]
        water_filter_cartridge: ["activated carbon", "ion exchange resin", "polypropylene shell"]
        candle: ["wax (paraffin or soy)", "cotton wick"]
        ink_cartridge: ["pigment ink", "polyethylene shell"]
      battery_chemistry: "none"
    safety_sealed:
      primary_materials: ["ABS plastic", "lithium battery", "electronic sensor assembly"]
      battery_chemistry: "Li-ion (unspecified)"
    software_dependent_electronics:
      primary_materials: ["ABS plastic", "PCB assembly", "motor/actuator", "lithium battery"]
      battery_chemistry: "Li-ion (unspecified)"
    battery_bearing_electronics:
      primary_materials: ["ABS plastic", "lithium battery cells", "PCB", "rare earth magnets"]
      battery_chemistry: "Li-ion (unspecified)"
    single_use_packaging:
      primary_materials: ["corrugated cardboard", "kraft paper", "water-based adhesive"]
      battery_chemistry: "none"


# -----------------------------------------------------------------------------
# TAXONOMY GOVERNANCE  (v1.4)
# -----------------------------------------------------------------------------
# Machine-readable governance policy for taxonomy management, rating review
# cadence, republishing thresholds, sub-category approval, and slug integrity.
# Adopted per RES-1208 (CEO sign-off). Implements review-by-exception with
# random-sample audits — the Hybrid/tier-1 model from the original RES-1208
# spec was superseded (2026-06-11 revision).

governance:

  # ---- Review Policy --------------------------------------------------------
  # Ratings are reviewed by exception: weekly diffs detect score-affecting
  # changes, and only materially changed ratings enter the human review queue.
  # Unchanged ratings auto-refresh last_reviewed_at quarterly. A random sample
  # of unchanged ratings is pulled each quarter for audit integrity.
  review_policy:
    mode: review_by_exception
    delta_threshold_hip_points: 0.5
    boundary_crossings_force_review:
      - tier_band
      - mark_threshold
    unchanged_review_date_refresh_cadence: quarterly
    methodology_bump_triggers_full_review: true
    random_sample_audits:
      enabled: true
      target_fraction_per_quarter: 0.05
      weighting: commercial_activity
      weighting_signals:
        - "categories with active verified ratings"
        - "categories with paid HIP Marks"

  # ---- Republish Thresholds -------------------------------------------------
  # A re-scored rating is only republished (new page version, sitemap ping,
  # manufacturer notification) if the delta exceeds these thresholds.
  # Sub-threshold movements are logged but not published.
  republish_thresholds:
    delta_hip_points: 0.5
    boundary_crossings_force_republish:
      - tier_band
      - mark_threshold
    methodology_bump_forces_republish: true

  # ---- Sub-category Rule ----------------------------------------------------
  # When a sub-category split is warranted within an existing category.
  # A new sub-category requires material differences in the dimensions below,
  # a >20% expected lifespan difference, a written justification, and dual
  # approval from CTO and methodology owner.
  subcategory_rule:
    material_difference_dimensions:
      - MSI
      - SCR
      - RC
      - RI
    lifespan_difference_threshold_pct: 20
    requires_justification: true
    requires_approval_from:
      - cto
      - methodology_owner
    justification_fields:
      - justification
      - approved_by

  # ---- Slug Policy ----------------------------------------------------------
  # Published category slugs are immutable. Renames emit a 301 redirect from
  # the retired slug to the new canonical slug. Old slugs are never reused.
  slug_policy:
    mutable_after_publish: false
    rename_redirect_status: 301
    reuse_old_slugs: false

  # ---- Audit Log Schema -----------------------------------------------------
  # All score movements — whether republished or not — are logged for audit.
  # Random-sample audits are logged alongside diff-driven entries.
  audit_log:
    log_sub_threshold_movements: true
    movement_fields:
      - timestamp
      - category
      - old_hip_score
      - new_hip_score
      - dimension_deltas
      - methodology_version
      # Provenance triple (methodology v1.5, RES-1621): lets an ISO auditor
      # reconstruct the data + model + rating version behind any single log entry.
      # source_snapshot_id is null until the score.py snapshot wiring (child A)
      # lands; scoring_model / rating_version_id populate from the result dict.
      - source_snapshot_id
      - scoring_model
      - rating_version_id
      - republished
      - reason
    log_sampled_audits: true
    sampled_audit_fields:
      - timestamp
      - category
      - sampling_cycle_id
      - sampling_quarter
      - review_outcome
      - reviewer

  # ---- Rating Lifecycle -----------------------------------------------------
  # Two-tier review policy (methodology v1.5, RES-1621 / RES-1378 §3.3).
  # ISO 14024 §7.6: the re-evaluation period is declared in advance and
  # disclosed on the rating page. Two tiers balance data freshness against the
  # cost of full re-scoring at scale:
  #   * interim review (annual)  — trigger check + evidence sweep. NOT a forced
  #                                full re-score. Populates `next_review`.
  #   * full re-score (2-yearly) — complete re-rating. Populates `re_rating_due`.
  #                                Tallies with the 24-month HIP Mark licence
  #                                (pages/pricing.md, rating-terms.md §7.3): a
  #                                rating and its mark licence expire together.
  rating_lifecycle:
    validity_period_years: 2          # full re-score due (re_rating_due = +2y)
    interim_review_period_years: 1    # annual interim checkpoint (next_review = +1y)
    expiry_grace_days: 30             # rating shows "review overdue" banner; not delisted
    rerating_triggers:
      - methodology_version_bump      # forces full re-score
      - model_version_change          # scoring-model swap/upgrade — a declared
                                      # re-rating trigger (the model has a fixed
                                      # training-data cutoff that ages against
                                      # moving source data), on par with a
                                      # methodology bump
      - source_snapshot_change        # any change to the external source set
      - manufacturer_disclosure       # verified-rating subject submits new evidence
      - boundary_crossing_event       # see governance.audit_log for definition
      - scheduled_expiry              # validity_period_years elapsed
    on_expiry:
      generic_ratings: rescore_with_current_methodology
      verified_ratings_with_active_mark: notify_manufacturer_30_days_before_then_rescore
    review_date_field_name: next_review
    rescore_due_field_name: re_rating_due

  # ---- Republish Notifications ----------------------------------------------
  # Who is told, and when, when a re-score forces republication (RES-1621 /
  # RES-1378 §3.6). republish_thresholds (above) decides WHETHER a movement is
  # republished; this block decides WHO is notified and on what SLA. ISO 14024
  # §6.2 expects material changes to be communicated to interested parties; for
  # verified ratings with an active HIP Mark the manufacturer is a stakeholder.
  republish_notifications:
    channels:
      - sitemap_ping                  # search-engine reindex on every republish
      - rating_page_version_bump      # new immutable version_id + changelog entry
      - manufacturer_email            # verified ratings only, to the mark contact
    mark_holder_notice_days: 30       # >=30-day notice before a mark-withdrawing drop
    # A "mark-withdrawing" drop is a re-score that pushes the HIP Score below the
    # mark threshold the manufacturer is licensed against. The mark is not
    # withdrawn on the day of the drop: the mark holder is notified >=30 days in
    # advance so they can respond (submit new evidence, dispute, or wind down
    # mark use). The public generic rating updates immediately; the licensed
    # mark's withdrawal is what is deferred by the notice window.
    triggers:
      score_drop_below_licensed_mark_threshold: notify_then_withdraw_after_notice
      score_drop_within_band: notify_only
      methodology_bump_republish: notify_only
    notify_within_days:
      generic_rating_republish: 1     # sitemap + page version bump are ~immediate
      verified_rating_manufacturer: 5 # manufacturer email within 5 working days
