feat(seed-saving): per-crop 'how to save this seed' guidance
A bundled, curated knowledge layer — the differentiator of a serious seed app. For a variety's crop it shows how the plant reproduces and what it takes to keep the variety true: life cycle, pollination (self/cross + insect/wind), isolation distance, how many plants to save from, dry/wet processing, a difficulty pill, and a short tip — all in human words. - assets/catalog/seed_saving.json: curated public-domain data (Seed to Seed / Seed Savers), keyed by botanical FAMILY (defaults) with per-species/genus OVERRIDES that win — so e.g. Vicia faba is correctly insect-cross-pollinated despite the selfing Fabaceae default, and maize is wind-pollinated with a large population. Notes are locale-keyed (es/en), extensible to any language — a starter set, not a ceiling. - domain/seed_saving.dart (pure): enums + SeedSavingGuide (merge, note fallback) + SeedSavingData.guideFor (species → genus → family). - data/seed_saving_catalog.dart: loads the asset once into an in-memory singleton (no DB table, no migration); injector loads it at startup. - VarietyDetail gains (from the linked species — the reliable key, vs the editable category); detail screen shows a _SeedSavingView when a guide resolves. - i18n seedSaving block (labels + enum values + params) in en/es/pt/ast. - Tests: domain lookup/merge, the real asset's key corrections, and the detail section shows/hides. 314 suite tests green; analyze clean.
This commit is contained in:
parent
bfff95fe8d
commit
7c2e3f207f
19 changed files with 954 additions and 2 deletions
47
apps/app_seeds/assets/catalog/seed_saving.json
Normal file
47
apps/app_seeds/assets/catalog/seed_saving.json
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"version": 1,
|
||||
"note": "Curated seed-saving guidance (public-domain horticultural knowledge, e.g. Ashworth 'Seed to Seed', Seed Savers Exchange). Keyed by botanical family (defaults) with per-species/genus overrides that win. Distances in metres are conservative home-garden ranges for keeping a variety reasonably true; plant counts keep enough genetic diversity. `note` is a locale-keyed map, extensible to any language. This is a starter set, not a ceiling.",
|
||||
"families": {
|
||||
"Solanaceae": { "lifeCycle": "annual", "pollination": "self", "vector": "self", "isolationMinM": 3, "isolationMaxM": 15, "minPlants": 1, "recommendedPlants": 6, "processing": "wet", "difficulty": "easy" },
|
||||
"Fabaceae": { "lifeCycle": "annual", "pollination": "self", "vector": "self", "isolationMinM": 3, "isolationMaxM": 20, "minPlants": 1, "recommendedPlants": 10, "processing": "dry", "difficulty": "easy" },
|
||||
"Cucurbitaceae": { "lifeCycle": "annual", "pollination": "cross", "vector": "insect", "isolationMinM": 400, "isolationMaxM": 1600, "minPlants": 6, "recommendedPlants": 12, "processing": "wet", "difficulty": "medium" },
|
||||
"Brassicaceae": { "lifeCycle": "biennial", "pollination": "cross", "vector": "insect", "isolationMinM": 800, "isolationMaxM": 1600, "minPlants": 6, "recommendedPlants": 20, "processing": "dry", "difficulty": "hard" },
|
||||
"Asteraceae": { "lifeCycle": "annual", "pollination": "self", "vector": "self", "isolationMinM": 3, "isolationMaxM": 8, "minPlants": 1, "recommendedPlants": 12, "processing": "dry", "difficulty": "easy" },
|
||||
"Apiaceae": { "lifeCycle": "biennial", "pollination": "cross", "vector": "insect", "isolationMinM": 300, "isolationMaxM": 1600, "minPlants": 5, "recommendedPlants": 20, "processing": "dry", "difficulty": "hard" },
|
||||
"Amaranthaceae": { "lifeCycle": "biennial", "pollination": "cross", "vector": "wind", "isolationMinM": 800, "isolationMaxM": 1600, "minPlants": 6, "recommendedPlants": 20, "processing": "dry", "difficulty": "hard" },
|
||||
"Chenopodiaceae": { "lifeCycle": "biennial", "pollination": "cross", "vector": "wind", "isolationMinM": 800, "isolationMaxM": 1600, "minPlants": 6, "recommendedPlants": 20, "processing": "dry", "difficulty": "hard" },
|
||||
"Amaryllidaceae": { "lifeCycle": "biennial", "pollination": "cross", "vector": "insect", "isolationMinM": 300, "isolationMaxM": 1600, "minPlants": 6, "recommendedPlants": 20, "processing": "dry", "difficulty": "medium" },
|
||||
"Alliaceae": { "lifeCycle": "biennial", "pollination": "cross", "vector": "insect", "isolationMinM": 300, "isolationMaxM": 1600, "minPlants": 6, "recommendedPlants": 20, "processing": "dry", "difficulty": "medium" },
|
||||
"Poaceae": { "lifeCycle": "annual", "pollination": "self", "vector": "self", "isolationMinM": 3, "isolationMaxM": 20, "minPlants": 20, "recommendedPlants": 40, "processing": "dry", "difficulty": "medium" },
|
||||
"Lamiaceae": { "lifeCycle": "perennial", "pollination": "cross", "vector": "insect", "isolationMinM": 45, "isolationMaxM": 150, "minPlants": 5, "recommendedPlants": 20, "processing": "dry", "difficulty": "medium" },
|
||||
"Malvaceae": { "lifeCycle": "annual", "pollination": "mixed", "vector": "insect", "isolationMinM": 150, "isolationMaxM": 500, "minPlants": 5, "recommendedPlants": 12, "processing": "dry", "difficulty": "easy" }
|
||||
},
|
||||
"species": {
|
||||
"Solanum lycopersicum": { "pollination": "self", "isolationMinM": 3, "isolationMaxM": 6, "minPlants": 1, "recommendedPlants": 5, "processing": "wet", "difficulty": "easy", "note": { "es": "Casi siempre se autopoliniza: fácil de mantener pura. Fermenta la semilla con su pulpa 2–3 días, lava y seca.", "en": "Almost always self-pollinates — easy to keep pure. Ferment the seed in its pulp for 2–3 days, then rinse and dry." } },
|
||||
"Capsicum annuum": { "pollination": "mixed", "vector": "insect", "isolationMinM": 8, "isolationMaxM": 150, "minPlants": 2, "recommendedPlants": 6, "processing": "dry", "difficulty": "easy", "note": { "es": "Se autopoliniza pero los insectos cruzan algo: separa los picantes de los dulces.", "en": "Self-pollinates but insects cross it somewhat — keep hot and sweet types apart." } },
|
||||
"Solanum melongena": { "pollination": "self", "isolationMinM": 6, "isolationMaxM": 15, "processing": "wet", "difficulty": "easy" },
|
||||
"Phaseolus vulgaris": { "pollination": "self", "vector": "self", "isolationMinM": 3, "isolationMaxM": 6, "minPlants": 1, "recommendedPlants": 10, "processing": "dry", "difficulty": "easy" },
|
||||
"Pisum sativum": { "pollination": "self", "vector": "self", "isolationMinM": 3, "isolationMaxM": 6, "minPlants": 1, "recommendedPlants": 10, "processing": "dry", "difficulty": "easy" },
|
||||
"Vicia faba": { "pollination": "cross", "vector": "insect", "isolationMinM": 180, "isolationMaxM": 1000, "minPlants": 10, "recommendedPlants": 50, "processing": "dry", "difficulty": "medium", "note": { "es": "¡Ojo! El haba SÍ se cruza por insectos, al revés que otras leguminosas: aíslala o cultiva una sola variedad.", "en": "Careful — unlike most legumes, faba beans DO cross via insects. Isolate them or grow a single variety." } },
|
||||
"Cucumis sativus": { "pollination": "cross", "vector": "insect", "isolationMinM": 400, "isolationMaxM": 1600, "processing": "wet", "difficulty": "medium" },
|
||||
"Cucurbita pepo": { "pollination": "cross", "vector": "insect", "isolationMinM": 400, "isolationMaxM": 1600, "minPlants": 6, "processing": "wet", "difficulty": "medium", "note": { "es": "Se cruza con calabacines, calabazas de verano y algunas de invierno de su especie. Poliniza a mano y cierra la flor para mantenerla pura.", "en": "Crosses with courgettes, summer squash and some winter squash of its species. Hand-pollinate and tape the flower to keep it pure." } },
|
||||
"Cucurbita maxima": { "pollination": "cross", "vector": "insect", "isolationMinM": 400, "isolationMaxM": 1600, "processing": "wet", "difficulty": "medium" },
|
||||
"Cucurbita moschata": { "pollination": "cross", "vector": "insect", "isolationMinM": 400, "isolationMaxM": 1600, "processing": "wet", "difficulty": "medium" },
|
||||
"Cucumis melo": { "pollination": "cross", "vector": "insect", "isolationMinM": 400, "isolationMaxM": 1600, "processing": "wet", "difficulty": "medium" },
|
||||
"Citrullus lanatus": { "pollination": "cross", "vector": "insect", "isolationMinM": 400, "isolationMaxM": 1600, "processing": "wet", "difficulty": "medium" },
|
||||
"Lactuca sativa": { "pollination": "self", "vector": "self", "isolationMinM": 3, "isolationMaxM": 8, "minPlants": 1, "recommendedPlants": 12, "processing": "dry", "difficulty": "easy", "note": { "es": "Se autopoliniza: muy fácil. Deja subir a flor y recoge la semilla con vilano cuando seque.", "en": "Self-pollinating and very easy. Let it bolt and collect the fluffy seed as it dries." } },
|
||||
"Helianthus annuus": { "pollination": "cross", "vector": "insect", "isolationMinM": 800, "isolationMaxM": 1600, "minPlants": 5, "recommendedPlants": 20, "processing": "dry", "difficulty": "medium" },
|
||||
"Daucus carota": { "lifeCycle": "biennial", "pollination": "cross", "vector": "insect", "isolationMinM": 300, "isolationMaxM": 1600, "minPlants": 5, "recommendedPlants": 40, "processing": "dry", "difficulty": "hard", "note": { "es": "Bienal: da semilla el segundo año. Se cruza con la zanahoria silvestre (encaje de la reina Ana).", "en": "Biennial — seeds in its second year. Crosses with wild carrot (Queen Anne's lace)." } },
|
||||
"Beta vulgaris": { "lifeCycle": "biennial", "pollination": "cross", "vector": "wind", "isolationMinM": 800, "isolationMaxM": 3200, "minPlants": 6, "recommendedPlants": 30, "processing": "dry", "difficulty": "hard", "note": { "es": "Polen por viento a mucha distancia: remolacha y acelga se cruzan entre sí. Cultiva solo una para semilla.", "en": "Wind-borne pollen travels far — beet and chard cross each other. Grow only one for seed." } },
|
||||
"Spinacia oleracea": { "lifeCycle": "annual", "pollination": "cross", "vector": "wind", "isolationMinM": 800, "isolationMaxM": 1600, "minPlants": 6, "recommendedPlants": 30, "processing": "dry", "difficulty": "medium" },
|
||||
"Allium cepa": { "lifeCycle": "biennial", "pollination": "cross", "vector": "insect", "isolationMinM": 300, "isolationMaxM": 1600, "processing": "dry", "difficulty": "medium" },
|
||||
"Brassica oleracea": { "lifeCycle": "biennial", "pollination": "cross", "vector": "insect", "isolationMinM": 800, "isolationMaxM": 1600, "minPlants": 6, "recommendedPlants": 20, "processing": "dry", "difficulty": "hard", "note": { "es": "Coles, brócoli, coliflor, col rizada… todos son la MISMA especie y se cruzan entre sí. Aísla bien y guarda de varias plantas.", "en": "Cabbage, broccoli, cauliflower, kale… all the SAME species and cross freely. Isolate well and save from several plants." } },
|
||||
"Brassica rapa": { "lifeCycle": "biennial", "pollination": "cross", "vector": "insect", "isolationMinM": 800, "isolationMaxM": 1600, "processing": "dry", "difficulty": "hard" },
|
||||
"Raphanus sativus": { "lifeCycle": "annual", "pollination": "cross", "vector": "insect", "isolationMinM": 300, "isolationMaxM": 800, "processing": "dry", "difficulty": "medium" },
|
||||
"Zea mays": { "lifeCycle": "annual", "pollination": "cross", "vector": "wind", "isolationMinM": 200, "isolationMaxM": 800, "minPlants": 20, "recommendedPlants": 100, "processing": "dry", "difficulty": "medium", "note": { "es": "Polen por viento: se cruza con cualquier otro maíz cercano. Guarda semilla de muchas plantas (100+) para que no pierda vigor.", "en": "Wind-pollinated — crosses with any nearby maize. Save seed from many plants (100+) so it doesn't lose vigour." } },
|
||||
"Ocimum basilicum": { "lifeCycle": "annual", "pollination": "mixed", "vector": "insect", "isolationMinM": 45, "isolationMaxM": 150, "minPlants": 5, "processing": "dry", "difficulty": "easy" },
|
||||
"Coriandrum sativum": { "lifeCycle": "annual", "pollination": "cross", "vector": "insect", "isolationMinM": 45, "isolationMaxM": 400, "processing": "dry", "difficulty": "easy" },
|
||||
"Petroselinum crispum": { "lifeCycle": "biennial", "pollination": "cross", "vector": "insect", "isolationMinM": 300, "isolationMaxM": 800, "processing": "dry", "difficulty": "hard" },
|
||||
"Abelmoschus esculentus": { "pollination": "mixed", "vector": "insect", "isolationMinM": 150, "isolationMaxM": 500, "processing": "dry", "difficulty": "easy" }
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue