# Contributing & Methodology

This document defines how a product earns a place in PayNowSaveLater and how every entry is verified. It is written to be followed by humans **and** by agents adding entries on a user's behalf.

## The evidence standard

A product qualifies only if it demonstrates **durability worth a price premium** — it should outlast a cheap equivalent enough to cost less over its life. Every claim must be backed by a citable source.

Each entry MUST:

1. **Validate** against `schema/product.schema.json` (`schema_version` `"1.0"`).
2. Populate the full `evidence` object: `country_of_origin`, `materials`, `warranty`, `repairability`, `longevity`.
3. Cite a `source_url` on each of warranty, repairability, and longevity.
4. List **≥1 `sources`** entry, each with `title`, `url`, and a one-line `quote` that directly supports a claim.
5. Carry a `last_verified` date. Re-verify at least every 12 months — facts (price, warranty terms) drift.

## Scoring repairability (0–10)

| Score | Meaning |
|---|---|
| 9–10 | Indefinitely rebuildable/restorable (resoleable boots, re-seasonable cast iron, maker repairs forever) |
| 6–8 | Serviceable with care; main wear part is restorable (re-sharpenable knives, repairable bags) |
| 3–5 | Some parts replaceable, but practical limits |
| 0–2 | Effectively disposable |

## Sourcing approach (hybrid)

We curate a shortlist, then require **evidence over opinion**:

- **Primary** sources first: the manufacturer's own warranty/repair page, spec sheet, country-of-origin statement.
- **Independent** corroboration second: long-term reviews, cobbler/repair shops, teardown/repairability analyses.
- **Community signal** (`bifl_signal`) third: r/BuyItForLife consensus is recorded as a *signal*, never as the sole basis for inclusion.

When sources conflict, record the more conservative claim and note the conflict in `cons` or the `terms` field.

## Trust rules (non-negotiable)

- **Placement is never sold.** `affiliate.is_paid_placement` MUST be `false`.
- Affiliate links are allowed but MUST carry a `disclosure` string.
- Ranking within a category reflects evidence (warranty strength, repairability, longevity, origin transparency) — not commission rate.

## Adding an entry

1. Add the product dict to `generate.py` (or write the `.json` directly to the category folder).
2. Run `python3 generate.py` to emit the `.json`, `.md`, category index, and refreshed `catalog.json`.
3. Validate every record:

   ```bash
   pip install jsonschema
   python3 - <<'PY'
   import json, glob, jsonschema
   schema = json.load(open("schema/product.schema.json"))
   for f in glob.glob("categories/*/*.json"):
       if f.endswith("index.json"): continue
       jsonschema.validate(json.load(open(f)), schema)
   print("All records valid.")
   PY
   ```

4. Confirm `last_verified` is today and each `source_url` resolves.
