hestia-earth-plugin 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. hestia_earth_plugin-0.1.1/.gitignore +32 -0
  2. hestia_earth_plugin-0.1.1/LICENSE +21 -0
  3. hestia_earth_plugin-0.1.1/PKG-INFO +123 -0
  4. hestia_earth_plugin-0.1.1/README.md +72 -0
  5. hestia_earth_plugin-0.1.1/pyproject.toml +75 -0
  6. hestia_earth_plugin-0.1.1/skills/debug-aggregation/SKILL.md +173 -0
  7. hestia_earth_plugin-0.1.1/skills/debug-model/SKILL.md +496 -0
  8. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/INDEX.md +22 -0
  9. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/background-model-crashes-on-retired-term.md +42 -0
  10. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/below-ground-residue-two-fields.md +26 -0
  11. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/cropping-intensity-plantation.md +13 -0
  12. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/emission-blocked-by-completeness.md +35 -0
  13. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/emission-failed-on-transformation.md +17 -0
  14. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/emission-failed-on-zero-driver.md +40 -0
  15. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/explain-value-no-verify.md +25 -0
  16. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/landcover-forest-share-flip.md +50 -0
  17. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/luc-emission-amortisation.md +31 -0
  18. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/missing-lookup.md +17 -0
  19. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/model-never-ran.md +20 -0
  20. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/multi-term-model-key.md +20 -0
  21. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/practice-not-gapfilled-allow-list.md +43 -0
  22. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/regrouped-emissions-dropped-by-boundary.md +72 -0
  23. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/should-run-false.md +16 -0
  24. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/tier-fell-back.md +26 -0
  25. hestia_earth_plugin-0.1.1/skills/debug-model/knowledge/zero-value.md +16 -0
  26. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/__init__.py +11 -0
  27. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/cli.py +189 -0
  28. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/config.py +117 -0
  29. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_aggregation/__init__.py +6 -0
  30. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_aggregation/cli.py +29 -0
  31. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_aggregation/split.py +900 -0
  32. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/__init__.py +6 -0
  33. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/check_staleness.py +137 -0
  34. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/cli.py +64 -0
  35. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/explain.py +228 -0
  36. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/fetch_issue.py +247 -0
  37. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/fetch_log.py +82 -0
  38. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/fetch_node.py +101 -0
  39. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/formula_eval.py +239 -0
  40. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/lib.py +159 -0
  41. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/privacy_check.py +327 -0
  42. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/probe_term.py +52 -0
  43. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/resolve.py +68 -0
  44. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/run_model.py +82 -0
  45. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/save_learnings.py +233 -0
  46. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/text_log.py +217 -0
  47. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/unpack_zip.py +258 -0
  48. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/upstream.py +55 -0
  49. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/debug_model/walk.py +244 -0
  50. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/install.py +113 -0
  51. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/knowledge.py +139 -0
  52. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/sources.py +293 -0
  53. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/summaries.py +24 -0
  54. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/updates.py +131 -0
  55. hestia_earth_plugin-0.1.1/src/hestia_earth/plugin/version.py +1 -0
  56. hestia_earth_plugin-0.1.1/tests/conftest.py +31 -0
  57. hestia_earth_plugin-0.1.1/tests/test_config.py +71 -0
  58. hestia_earth_plugin-0.1.1/tests/test_install.py +72 -0
  59. hestia_earth_plugin-0.1.1/tests/test_knowledge.py +52 -0
  60. hestia_earth_plugin-0.1.1/tests/test_lib.py +75 -0
  61. hestia_earth_plugin-0.1.1/tests/test_sources.py +131 -0
  62. hestia_earth_plugin-0.1.1/tests/test_split.py +531 -0
  63. hestia_earth_plugin-0.1.1/tests/test_summaries.py +44 -0
  64. hestia_earth_plugin-0.1.1/tests/test_updates.py +121 -0
@@ -0,0 +1,32 @@
1
+ .DS_Store
2
+ node_modules/
3
+ __pycache__/
4
+ *.pyc
5
+ .pytest_cache/
6
+ .coverage
7
+ coverage.xml
8
+ htmlcov/
9
+ build/
10
+ dist/
11
+ *.egg-info/
12
+
13
+ # Local secrets — the plugin's config lives in the user's home folder, never here
14
+ .env
15
+ *.env
16
+
17
+ # Docs build output
18
+ site/
19
+ public/
20
+
21
+ # Local docs/dev virtualenv
22
+ .venv/
23
+
24
+ # Generated by scripts/build-skill-catalogue.py
25
+ docs/skills.md
26
+
27
+ # Copied from CONTRIBUTING.md by scripts/serve-docs.sh
28
+ docs/contributing.md
29
+
30
+ # Never commit a debugged node's data
31
+ *.jlog
32
+ *.zip
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) HESTIA
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,123 @@
1
+ Metadata-Version: 2.5
2
+ Name: hestia-earth-plugin
3
+ Version: 0.1.1
4
+ Summary: HESTIA skills for AI coding assistants — debug a HESTIA model on a real node from Claude Code, Codex or Antigravity.
5
+ Project-URL: Homepage, https://hestia-earth.gitlab.io/hestia-plugin/
6
+ Project-URL: Repository, https://gitlab.com/hestia-earth/hestia-plugin
7
+ Project-URL: Issues, https://gitlab.com/hestia-earth/hestia-plugin/-/issues
8
+ Author: HESTIA
9
+ License: MIT License
10
+
11
+ Copyright (c) HESTIA
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Keywords: agent,antigravity,claude,codex,hestia,lca,skill
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Intended Audience :: Science/Research
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Topic :: Scientific/Engineering
37
+ Requires-Python: >=3.10
38
+ Requires-Dist: hestia-earth-utils>=0.17
39
+ Requires-Dist: requests>=2.28
40
+ Provides-Extra: dev
41
+ Requires-Dist: black; extra == 'dev'
42
+ Requires-Dist: flake8; extra == 'dev'
43
+ Requires-Dist: flake8-print; extra == 'dev'
44
+ Requires-Dist: hestia-earth-aggregation; extra == 'dev'
45
+ Requires-Dist: pytest; extra == 'dev'
46
+ Requires-Dist: pytest-cov; extra == 'dev'
47
+ Provides-Extra: models
48
+ Requires-Dist: hestia-earth-models>=0.80; extra == 'models'
49
+ Requires-Dist: hestia-earth-orchestrator>=0.6; extra == 'models'
50
+ Description-Content-Type: text/markdown
51
+
52
+ # HESTIA plugin
53
+
54
+ HESTIA skills for AI coding assistants. Ask Claude Code, Codex or Antigravity a question about
55
+ HESTIA data — why a model failed on your Cycle, where an aggregated number came from — and get an
56
+ answer built from what HESTIA actually computed rather than from guesswork.
57
+
58
+ **This is public.** It is published to PyPI as `hestia-earth-plugin`, and works against the public
59
+ HESTIA API, the public data downloads and the public `hestia-engine-models` repository — no
60
+ checkout, no internal access and no credential is required to use it.
61
+
62
+ ```bash
63
+ pip install hestia-earth-plugin # or: uv tool install hestia-earth-plugin
64
+ hestia-plugin install # register the skills with your assistant
65
+ ```
66
+
67
+ Then open your assistant and ask.
68
+
69
+ Until the first release lands on PyPI, install from the repository instead:
70
+ `pip install git+https://gitlab.com/hestia-earth/hestia-plugin.git`.
71
+
72
+ ## The skills
73
+
74
+ | | |
75
+ | --- | --- |
76
+ | **`/debug-model`** | Why a model failed on a Cycle, Site or ImpactAssessment, or why a value is what it is. Reads the run log the platform stored, checks the model's documented formula against it, and walks the failure upstream to the root cause. |
77
+ | **`/debug-aggregation`** | Where a number on an aggregation page came from. Rebuilds the weighted mean from the underlying-data download, and names the step — zero-filling, sub-system weighting — that moved it. |
78
+
79
+ More are being moved across; the [Skills](https://hestia-earth.gitlab.io/hestia-plugin/skills/)
80
+ page is generated from the skills themselves, so it is always the current list.
81
+
82
+ ## Documentation
83
+
84
+ **<https://hestia-earth.gitlab.io/hestia-plugin>**
85
+
86
+ - **[Install](https://hestia-earth.gitlab.io/hestia-plugin/)** — every assistant it supports, and where each one reads its skills
87
+ - **[Configure](https://hestia-earth.gitlab.io/hestia-plugin/configure/)** — what a HESTIA API token buys you, and what works without one
88
+ - **[Skills](https://hestia-earth.gitlab.io/hestia-plugin/skills/)** — the full catalogue, generated from the skills themselves
89
+ - **[How it works](https://hestia-earth.gitlab.io/hestia-plugin/how-it-works/)** — the division of labour between the assistant and the tools, and what each skill reads
90
+ - **[Troubleshooting](https://hestia-earth.gitlab.io/hestia-plugin/troubleshooting/)**
91
+ - **[Contributing](https://hestia-earth.gitlab.io/hestia-plugin/contributing/)** — adding a skill, and what must never be committed
92
+
93
+ Kept there rather than here so each thing is written down once: the install steps lived in
94
+ both places until they disagreed.
95
+
96
+ ## Working on the plugin
97
+
98
+ Each skill is a folder in `skills/` — a `SKILL.md` your assistant reads, and any `knowledge/`
99
+ playbooks it consults before diagnosing anything. The deterministic tools they call are in
100
+ `src/hestia_earth/plugin/`, one package per skill; nothing there talks to an LLM.
101
+
102
+ ```bash
103
+ pip install -e '.[dev,models]'
104
+ pytest && black src tests && flake8
105
+ hestia-plugin install # re-run after every change to a SKILL.md
106
+ ```
107
+
108
+ To preview a docs change:
109
+
110
+ ```bash
111
+ scripts/serve-docs.sh # http://127.0.0.1:8000, rebuilding as you edit
112
+ scripts/serve-docs.sh --build # one-shot --strict build, the same gate CI runs
113
+ ```
114
+
115
+ It creates a `.venv` on first run and builds the two generated pages — `docs/skills.md` and
116
+ `docs/contributing.md` are git-ignored.
117
+
118
+ Merge requests target `master`. The rest — commits, playbooks — is in
119
+ [CONTRIBUTING.md](CONTRIBUTING.md), which is also the source of the Contributing page.
120
+
121
+ ## License
122
+
123
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,72 @@
1
+ # HESTIA plugin
2
+
3
+ HESTIA skills for AI coding assistants. Ask Claude Code, Codex or Antigravity a question about
4
+ HESTIA data — why a model failed on your Cycle, where an aggregated number came from — and get an
5
+ answer built from what HESTIA actually computed rather than from guesswork.
6
+
7
+ **This is public.** It is published to PyPI as `hestia-earth-plugin`, and works against the public
8
+ HESTIA API, the public data downloads and the public `hestia-engine-models` repository — no
9
+ checkout, no internal access and no credential is required to use it.
10
+
11
+ ```bash
12
+ pip install hestia-earth-plugin # or: uv tool install hestia-earth-plugin
13
+ hestia-plugin install # register the skills with your assistant
14
+ ```
15
+
16
+ Then open your assistant and ask.
17
+
18
+ Until the first release lands on PyPI, install from the repository instead:
19
+ `pip install git+https://gitlab.com/hestia-earth/hestia-plugin.git`.
20
+
21
+ ## The skills
22
+
23
+ | | |
24
+ | --- | --- |
25
+ | **`/debug-model`** | Why a model failed on a Cycle, Site or ImpactAssessment, or why a value is what it is. Reads the run log the platform stored, checks the model's documented formula against it, and walks the failure upstream to the root cause. |
26
+ | **`/debug-aggregation`** | Where a number on an aggregation page came from. Rebuilds the weighted mean from the underlying-data download, and names the step — zero-filling, sub-system weighting — that moved it. |
27
+
28
+ More are being moved across; the [Skills](https://hestia-earth.gitlab.io/hestia-plugin/skills/)
29
+ page is generated from the skills themselves, so it is always the current list.
30
+
31
+ ## Documentation
32
+
33
+ **<https://hestia-earth.gitlab.io/hestia-plugin>**
34
+
35
+ - **[Install](https://hestia-earth.gitlab.io/hestia-plugin/)** — every assistant it supports, and where each one reads its skills
36
+ - **[Configure](https://hestia-earth.gitlab.io/hestia-plugin/configure/)** — what a HESTIA API token buys you, and what works without one
37
+ - **[Skills](https://hestia-earth.gitlab.io/hestia-plugin/skills/)** — the full catalogue, generated from the skills themselves
38
+ - **[How it works](https://hestia-earth.gitlab.io/hestia-plugin/how-it-works/)** — the division of labour between the assistant and the tools, and what each skill reads
39
+ - **[Troubleshooting](https://hestia-earth.gitlab.io/hestia-plugin/troubleshooting/)**
40
+ - **[Contributing](https://hestia-earth.gitlab.io/hestia-plugin/contributing/)** — adding a skill, and what must never be committed
41
+
42
+ Kept there rather than here so each thing is written down once: the install steps lived in
43
+ both places until they disagreed.
44
+
45
+ ## Working on the plugin
46
+
47
+ Each skill is a folder in `skills/` — a `SKILL.md` your assistant reads, and any `knowledge/`
48
+ playbooks it consults before diagnosing anything. The deterministic tools they call are in
49
+ `src/hestia_earth/plugin/`, one package per skill; nothing there talks to an LLM.
50
+
51
+ ```bash
52
+ pip install -e '.[dev,models]'
53
+ pytest && black src tests && flake8
54
+ hestia-plugin install # re-run after every change to a SKILL.md
55
+ ```
56
+
57
+ To preview a docs change:
58
+
59
+ ```bash
60
+ scripts/serve-docs.sh # http://127.0.0.1:8000, rebuilding as you edit
61
+ scripts/serve-docs.sh --build # one-shot --strict build, the same gate CI runs
62
+ ```
63
+
64
+ It creates a `.venv` on first run and builds the two generated pages — `docs/skills.md` and
65
+ `docs/contributing.md` are git-ignored.
66
+
67
+ Merge requests target `master`. The rest — commits, playbooks — is in
68
+ [CONTRIBUTING.md](CONTRIBUTING.md), which is also the source of the Contributing page.
69
+
70
+ ## License
71
+
72
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,75 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "hestia-earth-plugin"
7
+ dynamic = ["version"]
8
+ description = "HESTIA skills for AI coding assistants — debug a HESTIA model on a real node from Claude Code, Codex or Antigravity."
9
+ readme = "README.md"
10
+ license = { file = "LICENSE" }
11
+ requires-python = ">=3.10"
12
+ authors = [{ name = "HESTIA" }]
13
+ keywords = ["hestia", "agent", "skill", "claude", "codex", "antigravity", "lca"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Science/Research",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Topic :: Scientific/Engineering",
20
+ ]
21
+ dependencies = [
22
+ "requests>=2.28",
23
+ "hestia-earth-utils>=0.17",
24
+ ]
25
+
26
+ [project.optional-dependencies]
27
+ # Everything needed to re-run the models locally, rather than reading the log the
28
+ # platform already produced. Heavy (pandas, shapely, …), so it is opt-in.
29
+ models = [
30
+ "hestia-earth-models>=0.80",
31
+ "hestia-earth-orchestrator>=0.6",
32
+ ]
33
+ dev = [
34
+ "black",
35
+ "flake8",
36
+ # the fleet lints with flake8-print; ours ignores T201 on purpose (see .flake8),
37
+ # and installing the plugin is what keeps that decision visible rather than moot
38
+ "flake8-print",
39
+ "pytest",
40
+ "pytest-cov",
41
+ # test_split asserts the ported phase ratios still match the engine's own. That
42
+ # guard is only worth having if it runs in CI, so the engine is a test dependency
43
+ # rather than something the test skips when it is absent.
44
+ "hestia-earth-aggregation",
45
+ ]
46
+
47
+ [project.scripts]
48
+ hestia-plugin = "hestia_earth.plugin.cli:main"
49
+
50
+ [project.urls]
51
+ Homepage = "https://hestia-earth.gitlab.io/hestia-plugin/"
52
+ Repository = "https://gitlab.com/hestia-earth/hestia-plugin"
53
+ Issues = "https://gitlab.com/hestia-earth/hestia-plugin/-/issues"
54
+
55
+ [tool.hatch.version]
56
+ path = "src/hestia_earth/plugin/version.py"
57
+
58
+ [tool.hatch.build.targets.wheel]
59
+ packages = ["src/hestia_earth"]
60
+
61
+ # The skills are the product; they live at the repo root so Claude Code can load the
62
+ # repository directly as a plugin, and are folded into the wheel so a pip install can
63
+ # register them with any host.
64
+ [tool.hatch.build.targets.wheel.force-include]
65
+ "skills" = "hestia_earth/plugin/skills"
66
+
67
+ [tool.hatch.build.targets.sdist]
68
+ include = ["src", "skills", "tests", "README.md", "LICENSE", "pyproject.toml"]
69
+
70
+ [tool.black]
71
+ line-length = 88
72
+ target-version = ["py310"]
73
+
74
+ [tool.pytest.ini_options]
75
+ testpaths = ["tests"]
@@ -0,0 +1,173 @@
1
+ ---
2
+ name: debug-aggregation
3
+ description: Explain how a value on a HESTIA aggregation page was calculated — which underlying Cycles contributed, how zero-filling and sub-system weighting moved the result, and whether the value was averaged at all. Works from the "Download the underlying datasets" archive. Use when someone asks where an aggregated number came from, or why it looks too low, too high, or unlike the values they can see.
4
+ ---
5
+
6
+ # Debug an aggregated value
7
+
8
+ Answer "where did this number come from?" for a value on an aggregation page.
9
+
10
+ An aggregated value is a weighted mean of values that are **not stored** alongside it, so
11
+ nothing on the page explains it. Everything needed is in the underlying-data download, and
12
+ `hestia-plugin debug-aggregation split` extracts it. **This skill's job is the
13
+ interpretation**: turn the tool's output into a formula the reader can follow, with the real
14
+ numbers in it, and say which step accounts for the gap between "the values I can see" and
15
+ "the value that was published".
16
+
17
+ Nothing here needs a token or a checkout — the archive is a public download, and the
18
+ glossary lookups and `/terms/<id>` it consults are public too.
19
+
20
+ The user-facing version of this is the guide's
21
+ [Debugging](https://www.hestia.earth/guide/) page. If a run teaches you something durable,
22
+ it belongs there as well as here.
23
+
24
+ ## Input
25
+
26
+ `/debug-aggregation <path-to.zip> <termId>` — e.g. `/debug-aggregation "Oil palm, fruit.zip" diesel`.
27
+
28
+ - **The archive** is what the aggregation page's **Download the underlying datasets** gives you,
29
+ taken as **CSV (Compacted)**. Accept a `.zip`, or a single compacted CSV.
30
+ - **The Term** is a Term **id**, not a name: `diesel`, not `Diesel`. If the user gives a name,
31
+ convert it (lower camel case) and say what you used.
32
+
33
+ **With no arguments, ask — do not guess.** Two questions, in this order:
34
+ 1. **Which archive?** Ask the user to point at the `.zip`. If they have not downloaded one, tell
35
+ them: open the aggregation on the platform → download → **Download the underlying datasets** →
36
+ **CSV (Compacted)**. Stop until you have a path.
37
+ 2. **What would you like to know?** Offer the three things this can answer, since the right command
38
+ differs:
39
+ - *why is one value what it is* → a Term id, the main case;
40
+ - *which Cycles are in which sub-aggregation* → the split, no Term needed;
41
+ - *a Site measurement or management value* → needs `--node-type Site`.
42
+
43
+ Given only an archive and no Term, run the split (below) and show the groups, then ask which Term.
44
+
45
+ ## Steps
46
+
47
+ ### 1. Run the tool
48
+
49
+ ```bash
50
+ # the split: which Cycle is in which sub-aggregation
51
+ hestia-plugin debug-aggregation split --filepath "<archive>" --dest-folder <scratch>
52
+
53
+ # one Term, the main case
54
+ hestia-plugin debug-aggregation split --filepath "<archive>" --term <termId>
55
+
56
+ # a Site measurement or management Term
57
+ hestia-plugin debug-aggregation split --filepath "<archive>" --term <termId> --node-type Site
58
+ ```
59
+
60
+ Write the group CSVs to a scratch directory, never into a repository — the archive is the
61
+ user's data.
62
+
63
+ **Completeness is usually derived for you.** Emissions take the completeness of the Inputs they
64
+ carry, and the tool works that out. For an **input or product** it cannot, so it prints the areas
65
+ in the file — pick the matching one and re-run with `--completeness <area>`
66
+ (`ureaKgN` → `fertiliser`, `diesel` → `electricityFuel`, `seed` → `seed`). Without it you get the
67
+ values and the groups but not the zero-filling, which is usually the whole answer.
68
+
69
+ A Term can appear as **several blank nodes** and the tool reports each separately — that is
70
+ correct, not duplication (see "Why a Term appears more than once").
71
+
72
+ ### 2. Read the numbers before writing anything
73
+
74
+ From the output, for each blank node:
75
+ - `N nodes, R reporting a value` — how many Cycles/Sites reported anything;
76
+ - the per-group table — each sub-aggregation's count and mean;
77
+ - `complete for <area>: C` — the Cycles the value was averaged over, and the split of that into
78
+ reporting and zero-filled;
79
+ - `published by the aggregation: P over O observations`;
80
+ - the reconstruction table — the weights and the rebuilt total.
81
+
82
+ **`observations` is the first thing to check.** Present means the node was averaged and is
83
+ rebuildable. **Absent means it was recalculated** from the aggregated data rather than averaged —
84
+ background emissions are computed afresh from the aggregated Inputs once the aggregated Cycle
85
+ exists. There is nothing in the download to rebuild those from; say so plainly and stop rather than
86
+ presenting a total that cannot match.
87
+
88
+ ### 3. Write the explanation as a formula with the numbers in it
89
+
90
+ The published value is the **weighted mean of the zero-filled group means**:
91
+
92
+ $$P = \sum_{g} w_g \times \frac{\sum_{i \in g} v_i}{C_g}$$
93
+
94
+ - $v_i$ — the values the Cycles in group $g$ actually reported;
95
+ - $C_g$ — the Cycles in $g$ **complete** for the Term's completeness area, not the number that
96
+ reported. The difference is the zero-filling;
97
+ - $w_g$ — the sub-system weight, from the aggregated Cycle's `description`;
98
+ - $\sum_g C_g$ is the Term's published `observations`.
99
+
100
+ Then substitute. A good answer walks the three steps and names what each one costs, e.g.:
101
+
102
+ > **`ureaKgN`, published `29.56` kg N.**
103
+ >
104
+ > 1. **22 of the 35 Cycles report Urea**, averaging `105.1`. That is the figure you would get from
105
+ > the download unaided, and it is 3.6× the published value.
106
+ > 2. **All 35 are complete for `fertiliser`**, so the 13 reporting nothing each contribute a `0`:
107
+ > `2312.5 / 35 = 66.07`. This is why `observations` is 35 and not 22.
108
+ > 3. **The two sub-systems are weighted very differently** — irrigated `0.23%`, rainfed `99.77%`,
109
+ > from the country's irrigated area rather than from how many Cycles are in each group. The
110
+ > irrigated group holds 22 of the 35 Cycles and the higher mean (`87.72`) but almost none of the
111
+ > weight: `0.0023 × 87.72 + 0.9977 × 29.43 = 29.56`. ✓
112
+
113
+ Rules for this section:
114
+ - **Substitute real numbers** — a formula with symbols alone is not an answer.
115
+ - **Name the step that did the work.** Usually it is one of zero-filling or weighting; say which.
116
+ - **Say when it does not match**, and what is missing, rather than fudging. The tool prints the
117
+ percentage off.
118
+ - Keep the arithmetic checkable — show the products, not just the result.
119
+
120
+ ### 4. Answer what was actually asked
121
+
122
+ Two other shapes come up, and both are usually about a value that looks wrong:
123
+
124
+ - **"Which Cycle caused this?"** — the per-Cycle list is sorted by value, so the outlier is at the
125
+ top. Give its `@id`, its group, and the links: `https://www.hestia.earth/cycle/<id>`, its Site via
126
+ `site.@id`, its Source via `defaultSource.@id`. A Site is worth checking when the outlier is a
127
+ measurement or land cover, since several Cycles can share one Site.
128
+ - **"Why is this so much lower than the values I see?"** — nearly always zero-filling. Give the
129
+ reporting mean and the complete-set mean side by side, and the count of Cycles that contributed a
130
+ `0`.
131
+
132
+ ## Why a Term appears more than once
133
+
134
+ The compacted download qualifies a Term by the blank node it belongs to. Some qualifiers survive
135
+ aggregation and some do not, so the tool combines the ones that are dropped and keeps the rest
136
+ apart — matching what the aggregation publishes:
137
+
138
+ | Qualifier | Carried? | Consequence |
139
+ | --- | --- | --- |
140
+ | `operation`, `method`, `methodClassification` | dropped | combined into one node |
141
+ | `inputs` (on an emission) | carried | one node per causing Input |
142
+ | `depthLower` / `depthUpper` | carried | measurements aggregate per depth interval |
143
+ | `startDate` / `endDate` | carried | management is re-dated per aggregation period |
144
+
145
+ So `diesel` legitimately reports several nodes, and `clayContent` reports one per depth. Explain the
146
+ one the user asked about; do not average them together.
147
+
148
+ ## Things that will trip you up
149
+
150
+ - **The archive contains the aggregated node itself** (`aggregated = True`). It is the published
151
+ result, not an input to it. The tool excludes it and uses it as the source of the published
152
+ value, `observations` and the weights.
153
+ - **The underlying Cycles keep changing.** A download taken today may not reproduce a value computed
154
+ months ago — check the Cycles' `updatedAt` against the aggregation's creation date before
155
+ concluding the arithmetic is wrong. If they have moved, say so and suggest a
156
+ [data release](https://www.hestia.earth/guide/guide-accessing-data-data-releases) from around the
157
+ aggregation's date.
158
+ - **A missing value is `-`, not blank**, and booleans are `True`/`False`.
159
+ - **Plantation crops split on a third axis** (productive / preparation / non-productive). Those
160
+ phases are not sub-systems, so the `description` carries no weight for them and the reconstruction
161
+ stops after zero-filling. Say that rather than reporting a mismatch.
162
+ - **Primary products are rescaled** to the HESTIA default `dryMatter` before averaging. The tool
163
+ fetches the default and applies it; a product with no `dryMatter` property is not rescaled.
164
+
165
+ ## Guardrails
166
+
167
+ - Do not invent numbers. Every figure in the explanation comes from the tool's output or from
168
+ arithmetic you show.
169
+ - Do not present a reconstruction for a node with no `observations` — it was recalculated, not
170
+ averaged.
171
+ - If the archive has no file for the node type asked about, say which files it does contain.
172
+ - Keep the answer to the value asked about. Note other oddities separately rather than expanding the
173
+ investigation unasked.