Where the advisor lives — a proposal#
2026-10-08, decided 2026-10-09: option B, AGPL-3.0-or-later, named advise — the maintainer
adopted the recommendation, and the advisor now lives in modules/advise/, where this note
moved with it. Everything listed under "What B would add" was built with the move: the
module pack, the data manifest, the version stamp on every report and the import check
(tools/test_layering.py). Offline running from a regional bundle is still to come.
The problem#
modules/advise/advise.py LAT LON now tells a farmer what to grow, when to sow, which fruit
cultivars get their chill, what to fix in the soil, what bees and livestock face, and what
changes by the 2050s. That is layer 3 — the spec's decision support: agronomic models,
forecasting, simulation (v0 "Layers above") — and it is sitting inside layer zero, whose
first line says it "ships no end-user features". Nobody decided this; it accreted, one
useful tool at a time, from the plant-conditions plan. Three things now show the cost:
- Layer zero's language packs are mostly the advisor's. 89 of the 177 strings in
sdk/packs/*.jsonareadvise.*. A translator who volunteers for layer zero is asked to translate a crop report; a release of layer zero is held by a sentence about paraguayos. - The licences are muddled. The advisor's code carries the SDK's Apache-2.0 headers
in
tools/; its data sits indocs/notes/beside the CC-BY spec under five licences (CC0, CC BY 4.0, BSD-3, the studies GloBI cites); and if it is ever run as a service, the reference server's AGPL reasoning (keep hosted improvements open) applies to it at least as much as to the server. - It does not meet the bar the spec sets for layer 3. v0 asks that layer-3 models be "versioned and calibrated per site; confidence shown; suspect and stuck readings excluded". The advisor stamps no model or data version on its report, shows confidence only as "8 years in 10", and reads no farm's own readings at all yet.
What would move#
| moves (the advisor) | stays (layer zero and its validation) |
|---|---|
advise.py, plant_match.py, site_profile.py, dssat_crops.py, plant_conditions.py, globi_bees.py, interactions.py, chill_requirements.py, chill_requirements_pome.py, fruit_bloom.py, tunnel_gain.py, and their tests |
ismn_*.py, q5_encoding.py, packs.py, everything in sdk/, server/, sim/ |
the data: plant-list.csv, plant-characteristics-usda.csv, crop-parameters-dssat.csv (+ its licence), plant-bees-globi*.{csv,txt}, interactions.csv, chill-requirements.csv, the animal/fertilizer/nursery/structure lists |
the spec, and notes about layer zero (siting, spikes, Q-notes, validation) |
the advise.* pack strings, into the module's own pack |
the enum., term., unit., check., siting. strings |
the plan and results notes (plant-conditions.md, site-match-tennessee.md, hoop-houses.md, …) |
soil_survey.py is used by both: layer zero's flatline thresholds (Q24) and the
advisor's site profile. It stays in layer zero's tools/ and the advisor imports it —
dependencies point down, as v0 requires; layer zero never imports the advisor.
Options#
| where | for | against | |
|---|---|---|---|
| A | stay in tools/ (today) |
no work | contradicts layer zero's scope; packs and licences stay mixed; nothing enforces "dependencies point down" |
| B | modules/advise/ in this repository, with its own README, LICENSE, pack, data manifest and tests in make test |
one CI, one checkout, history kept; the move is mechanical; an import check in CI can enforce the direction | the repository grows; a module's release is still tied to the repository's |
| C | a separate repository, fieldmesh-advise |
the cleanest boundary; its own releases, licence and contributors; layer zero's repo returns to its scope | two CIs; cross-repo changes (a pack format change) need two PRs; premature while there is one maintainer |
Recommendation: B now, C when the advisor has a release cadence or a contributor of its
own. B fixes the scope, pack and licence problems at the cost of a few git mvs, and
leaves the C split as a later git subtree split with history intact.
What B would add beyond the move#
- A module pack. The pack format already namespaces by prefix; the module ships
modules/advise/packs/{en,es}.jsonholdingadvise.*, andi18nwould merge module packs over the base at load.make packschecks both. - A data manifest (
modules/advise/data/MANIFEST.csv): per file its source, licence, retrieval date and checksum, replacing the prose table inLICENSING.md. - A version stamp on every report: the module version, the data manifest's hash and the DSSAT commit, so a report can be reproduced and a changed recommendation explained — the spec's "models versioned".
- An import check in CI: nothing under
sdk/,server/orsim/may import frommodules/. - Offline. The advisor fetches NASA POWER, the soil survey, PLANTS and GloBI at run time (cached). Layer 4 must work offline, so the module should also be able to run from a pre-fetched regional bundle; that is a later step, noted so the layout leaves room for it.
Decisions for the maintainer#
- Where: A, B or C.
- Licence for the module's code: Apache-2.0 (like the SDK — easiest to embed in an app) or AGPL-3.0 (like the reference server — keeps a hosted advisor's improvements open). The data keeps its sources' licences either way.
- Name:
advise(what it does), or a name for the layer-3 family it starts (decide,plan).