ASSEMBLY-WP-0007-T02: ecological resource classes (renewables, materials, sinks); sinks bind the generative regime; grounding test passed; low-carbon lever

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 14913@bnt-lap001
Assistant-Session: add7ef69-b901-4756-9a67-34cf1125d96f
This commit is contained in:
tegwick 2026-10-13 23:11:25 +02:00
parent e05c8f100f
commit 8dd9e97d33
7 changed files with 277 additions and 1 deletions

View file

@ -40,6 +40,7 @@ cd simulations/gadm02 && python3 -B cross_border.py # coupled world US/EU/AR f
cd simulations/gadm02 && python3 -B world_scenarios.py # contexts X1–X4, hypothesis re-test, local vs. global
cd simulations/gadm02 && python3 -B exports.py # export channel and the "Argentina may thrive" hypothesis
cd simulations/gadm02 && python3 -B nonrival.py # GADM-0.5-dev rival vs. non-rival output across the band
cd simulations/gadm02 && python3 -B eco_classes.py # GADM-0.5-dev ecological resource classes
cd simulations/gadm02 && python3 -B matching.py && python3 -B matching.py --imm # model matching; IMM flip-detection acceptance test (~6 min)
```

View file

@ -58,3 +58,62 @@ generative regime 0.08 to 0.31.
5. **The generative regime's advantage is robust across the band** (+0.27 to
+0.31), slightly smaller than in GADM-0.4 (+0.29 to +0.34), because the
baseline also gains from the commons feed.
## 2. Ecological resource classes (T02)
### 2.1 Structure
`gadm05.simulate_eco` replaces the single E with three classes, each with
its own floor (0.20). The aggregate E used for output and VFAC is their
geometric mean.
| Class | Covers | Start (prior from indicators) | Regeneration |
|---|---|---|---|
| Er renewables | energy, land, freshwater, biosphere | 0.15 (all three land/water/biosphere boundaries breached, PHC 2025) | yes, at rest at start |
| Ed materials | depletable stocks | 0.45 (EU footprint 13.7 t/capita vs. a sustainable level of about 6–8 t) | none, or replenishment at rest (reserve growth) |
| Es sinks | climate, ocean acidification, novel entities, nutrient flows | 0.33 (2 of 6 sink-type boundaries safe) | yes, at rest at start |
Physical load (K_phys · dem · thr) draws 40/30/30 % on renewables, materials
and sinks. Compute load (K_Ω) draws 30/20/50 %. The sink load is scaled by
(1 − low-carbon electricity share, `lowc` 0.40, US-like). Recycling (`circ`
0.12, the EU circular material use rate) slows material depletion. These
shares are priors.
### 2.2 Results (`eco_classes.py`, `results/eco_classes.md`)
| | Strict material depletion | Material replenishment at rest |
|---|---|---|
| Renewables | below floor at start, every scenario | below floor at start, every scenario |
| Materials | cross the floor at t 25–70 (generative regime first, t 25–30) | never cross |
| Sinks | generative regime: t 29 (B4) to 83 (B1); others: never | same |
| Lowest class at t 100 | materials | renewables |
Organism growth (baseline, B4 − B1, relative change t 0 → 50): sinks
−0.036, renewables −0.032, materials −0.018.
Low-carbon electricity share (generative regime, replenishment at rest):
the sinks breach moves from t 49 / 37 / 29 (B2 / B3 / B4, share 0.4) to
t 87 / 66 / 52 (share 0.7, EU-like). At 0.9 there is no breach within 100
years.
### 2.3 Readings
1. **Grounding test passed:** organism growth binds sinks and renewables
(energy) before materials (`ParameterGrounding.md` § 3).
2. **The renewables class is already beyond its floor at the start.** The
single E (0.235) hid that one class is binding today while the others
still have headroom. Floors must be checked per class.
3. **Which class binds next depends on an unmeasured assumption.** With
strict depletion, materials bind first in every scenario. If reserve growth
keeps pace with use, they never do. Material replenishment needs grounding
(reserve-to-production ratios over time).
4. **The generative regime's ecological cost sits in the sinks.** It is the
only scenario that breaches the sink floor, and faster adoption brings the
breach forward (t 83 → 29). This makes BR-010 more specific: the regime's
problem is the sink load of its physical and compute activity, not output
as such.
5. **Low-carbon electricity is the decisive lever for organism-driven sink
load.** An EU-like share (0.7) delays the breach by 23–38 years; 0.9 avoids
it within the horizon. The effect is conservative: sink regeneration is
fitted so that each share starts at rest, so the lever acts only on the
growth of the load.

View file

@ -109,6 +109,12 @@ B1–B4). The split did not produce throughput decoupling (BR-010). New priors
Index) and `xn` 0.3 (about aX) need grounding: φ from task-level usage data
(L4), xn from open-licensing shares of AI-generated output.
**T02 result (2026-10-13, `models/GADM-0.5.md` § 2):** test passed.
Organism growth draws most on sinks (−0.036) and renewables (−0.032), and
least on materials (−0.018). New priors to ground: the class starting levels,
the load shares, and material replenishment (reserve growth). Which class
binds next depends on the replenishment.
## 4. Remaining open grounding needs
1. Commons investment `IX`: needs a mapping concept, not just data.

View file

@ -0,0 +1,76 @@
"""Ecological resource classes across the adoption band (ASSEMBLY-WP-0007-T02).
Which class binds first per scenario (GADM-Sectors-Scope.md § 2)? Does organism growth bind
energy and sinks before materials (ParameterGrounding.md § 3 test)?
Classes: renewables Er (energy, land, water, biosphere), materials Ed, sinks Es; floors 0.20.
Materials with strict depletion (rm 0) or replenishment at rest today (rm "rest").
Usage: python3 -B simulations/gadm02/eco_classes.py
"""
from __future__ import annotations
import sys
from pathlib import Path
sys.dont_write_bytecode = True
import gadm05 as g5 # noqa: E402
import grounding as gr # noqa: E402
from scenarios import load_all # noqa: E402
OUT = Path(__file__).resolve().parent / "results"
ANCHORS = list(gr.BAND)
NAMES = {"Er": "renewables", "Ed": "materials", "Es": "sinks"}
FLOOR = g5.ECO_PARAMS["eco_floor"]
def crossing(rows: list[dict], k: str) -> str:
if rows[0][k] < FLOOR:
return "below at start"
for r in rows:
if r[k] < FLOOR:
return f"t {r['t']:.0f}"
return "—"
def main() -> None:
OUT.mkdir(exist_ok=True)
scs = load_all()
var = {a: gr.variant(gr.BAND[a]) for a in ANCHORS}
lines = ["# GADM-0.5-dev: ecological resource classes across the band", "",
"Generated by `simulations/gadm02/eco_classes.py` (ASSEMBLY-WP-0007-T02). Floors 0.20 per class.",
"Starting levels and loads: `gadm05.py` (priors from measured indicators). Crossing = first year",
"below the floor. t = 100 levels.", ""]
res = {}
for rm in (0.0, "rest"):
lines += [f"## Materials replenishment: {'none (strict depletion)' if rm == 0.0 else 'at rest today'}", "",
"| Scenario | Anchor | Er / Ed / Es t100 | renewables below floor | materials below floor | sinks below floor | lowest at t100 |",
"|---|---|---|---|---|---|---|"]
for sc in ("baseline", "generative_regime", "attention_oligopoly"):
for a in ANCHORS:
rows = g5.simulate_eco({**scs[sc]["params"], **var[a][0]}, {**scs[sc]["init"], **var[a][1]},
eco={"rm": rm})
f = rows[-1]
res[(rm, sc, a)] = rows
low = min(g5.ECO, key=lambda k: f[k])
lines.append(f"| {scs[sc]['title']} | {a} | {f['Er']:.2f} / {f['Ed']:.2f} / {f['Es']:.2f} | "
f"{crossing(rows, 'Er')} | {crossing(rows, 'Ed')} | {crossing(rows, 'Es')} | {NAMES[low]} |")
lines.append("")
lines += ["## Organism growth: class draw attributable to adoption speed (baseline, B4 − B1)", "",
"Relative change of each class between t 0 and t 50, B4 minus B1 (negative = organisms draw more).", "",
"| Materials replenishment | renewables | materials | sinks | order (most hit first) |", "|---|---|---|---|---|"]
for rm in (0.0, "rest"):
rel = {}
for k in g5.ECO:
r4, r1 = res[(rm, "baseline", "B4")], res[(rm, "baseline", "B1")]
rel[k] = (r4[5][k] / r4[0][k] - 1) - (r1[5][k] / r1[0][k] - 1)
order = " > ".join(NAMES[k] for k in sorted(rel, key=lambda k: rel[k]))
lines.append(f"| {'none' if rm == 0.0 else 'at rest'} | {rel['Er']:+.3f} | {rel['Ed']:+.3f} | {rel['Es']:+.3f} | {order} |")
lines.append("")
(OUT / "eco_classes.md").write_text("\n".join(lines))
print("\n".join(lines))
if __name__ == "__main__":
main()

View file

@ -34,3 +34,83 @@ def throughput(row: dict, p: dict | None = None) -> float:
"""Physical throughput (ecological draw rate per unit of E): e1 K_phys dem thr + e2 K_Omega."""
p = {**PARAMS, **(p or {})}
return p["e1"] * row["Kp"] * row["dem"] * p["thr"] + p["e2"] * row["Ko"]
# --- ASSEMBLY-WP-0007-T02: ecological resource classes ----------------------------------------
# Er renewable capacity (energy, land, freshwater, biosphere), Ed depletable materials, Es sinks
# (climate, ocean acidification, novel entities, nutrient flows). Each class has its own floor; the
# aggregate E (used for output and VFAC) is their geometric mean. Scope: GADM-Sectors-Scope.md § 2.
#
# Starting levels (priors from measured indicators): Er 0.15 (land, freshwater and biosphere
# boundaries all breached, Planetary Health Check 2025), Es 0.33 (2 of 6 sink-type boundaries safe:
# ozone, aerosols), Ed 0.45 (EU material footprint 13.7 t/capita, Eurostat env_ac_mfa 2025, against a
# sustainable level of roughly 6-8 t). Aggregate (0.15 * 0.45 * 0.33)^(1/3) = 0.28 (E measured 0.235).
#
# Load split (priors): physical load K_phys * dem * thr draws 40 % on renewables, 30 % materials,
# 30 % sinks; compute load K_Omega draws 30 % renewables (energy, cooling water), 20 % materials
# (hardware turnover, 2-6 year economic life), 50 % sinks (electricity emissions). Class intensities
# are 3 x share x e1 or e2, so the mean relative draw matches the single-E model. Sink loads are
# scaled by (1 - lowc), the low-carbon electricity share. Renewables and sinks regenerate; the
# regeneration rates are fitted so that their starting levels are at rest. Materials do not
# regenerate; recycling (circ, circular material use rate) slows depletion.
ECO = ("Er", "Ed", "Es")
STOCKS_ECO = g4.STOCKS + ECO
ECO_PARAMS = {"eco": 0.0, "Er0": 0.15, "Ed0": 0.45, "Es0": 0.33,
"share_k": (0.4, 0.3, 0.3), "share_o": (0.3, 0.2, 0.5),
"lowc": 0.40, "circ": 0.12, "rr": None, "rs": None, "rm": 0.0, "eco_floor": 0.20}
# rm: material replenishment (reserve growth through discovery, substitution and recycling technology).
# 0 = strict depletion; "rest" = fitted so that today's material headroom is at rest.
def eco_E(s: dict) -> float:
return (max(1e-9, s["Er"]) * max(1e-9, s["Ed"]) * max(1e-9, s["Es"])) ** (1 / 3)
def _loads(s: dict, a: dict, p: dict) -> tuple[float, float]:
return s["Kp"] * a["dem"] * p["thr"], s["Ko"]
def _draws(s: dict, a: dict, p: dict, q: dict) -> tuple[float, float, float]:
lk, lo = _loads(s, a, p)
(rk, mk, sk), (ro, mo, so) = q["share_k"], q["share_o"]
dr = 3 * (rk * p["e1"] * lk + ro * p["e2"] * lo)
dm = 3 * (mk * p["e1"] * lk + mo * p["e2"] * lo) * (1 - q["circ"])
ds = 3 * (sk * p["e1"] * lk + so * p["e2"] * lo) * (1 - q["lowc"])
return dr, dm, ds
def simulate_eco(params: dict | None = None, init: dict | None = None, eco: dict | None = None,
T: float = 100.0, dt: float = 0.1, record_every: int = 10) -> list[dict]:
"""GADM-0.5 with ecological classes. Same loop as gadm04.simulate; E follows the classes."""
q = {**ECO_PARAMS, **(eco or {})}
p = {**PARAMS, **(params or {})}
s = {**g4.INIT, **(init or {})}
s.update({"Er": q["Er0"], "Ed": q["Ed0"], "Es": q["Es0"]})
s["E"] = eco_E(s)
if p["sent"] and p["sig_pb0"] is None:
_d, a0 = g4.derivatives(s, p)
p = {**p, "sig_pb0": g4.perceived_benefit(s, a0, g4.legislated(s, p))}
_d, a0 = g4.derivatives(s, p)
dr0, _dm0, ds0 = _draws(s, a0, p, q)
rr = q["rr"] if q["rr"] is not None else dr0 * s["Er"] / (1 - s["Er"])
rs = q["rs"] if q["rs"] is not None else ds0 * s["Es"] / (1 - s["Es"])
rm = _dm0 * s["Ed"] / (1 - s["Ed"]) if q["rm"] == "rest" else q["rm"]
rows = []
steps = int(round(T / dt))
for i in range(steps + 1):
d, a = g4.derivatives(s, p)
dr, dm, ds = _draws(s, a, p, q)
d["Er"] = rr * (1 - s["Er"]) - dr * s["Er"]
d["Ed"] = rm * (1 - s["Ed"]) - dm * s["Ed"]
d["Es"] = rs * (1 - s["Es"]) - ds * s["Es"]
d["E"] = 0.0
if i % record_every == 0:
row = {"t": round(i * dt, 6), **s, "P": g4.g3.total_p(s), "G": a["Gagg"],
**{k: a[k] for k in ("H", "A", "Ystar", "Yr", "Yn", "dem", "B", "V", "Vsel")}}
row["VFAC"] = g4.g2.vfac(row)
rows.append(row)
if i < steps:
s = {k: (max(0.0, s[k] + dt * d[k]) if k.startswith("N")
else min(1.0, max(0.0, s[k] + dt * d[k]))) for k in STOCKS_ECO}
s["E"] = eco_E(s)
return rows

View file

@ -0,0 +1,48 @@
# GADM-0.5-dev: ecological resource classes across the band
Generated by `simulations/gadm02/eco_classes.py` (ASSEMBLY-WP-0007-T02). Floors 0.20 per class.
Starting levels and loads: `gadm05.py` (priors from measured indicators). Crossing = first year
below the floor. t = 100 levels.
## Materials replenishment: none (strict depletion)
| Scenario | Anchor | Er / Ed / Es t100 | renewables below floor | materials below floor | sinks below floor | lowest at t100 |
|---|---|---|---|---|---|---|
| Baseline (current trends) | B1 | 0.16 / 0.09 / 0.32 | below at start | t 47 | — | materials |
| Baseline (current trends) | B2 | 0.20 / 0.12 / 0.35 | below at start | t 47 | — | materials |
| Baseline (current trends) | B3 | 0.18 / 0.10 / 0.29 | below at start | t 44 | — | materials |
| Baseline (current trends) | B4 | 0.14 / 0.07 / 0.22 | below at start | t 38 | — | materials |
| Generative regime | B1 | 0.08 / 0.02 / 0.19 | below at start | t 30 | t 83 | materials |
| Generative regime | B2 | 0.08 / 0.01 / 0.17 | below at start | t 28 | t 49 | materials |
| Generative regime | B3 | 0.08 / 0.01 / 0.15 | below at start | t 27 | t 37 | materials |
| Generative regime | B4 | 0.08 / 0.01 / 0.14 | below at start | t 25 | t 29 | materials |
| Attention oligopoly | B1 | 0.25 / 0.17 / 0.43 | below at start | t 70 | — | materials |
| Attention oligopoly | B2 | 0.25 / 0.17 / 0.40 | below at start | t 69 | — | materials |
| Attention oligopoly | B3 | 0.21 / 0.14 / 0.32 | below at start | t 56 | — | materials |
| Attention oligopoly | B4 | 0.16 / 0.09 / 0.23 | below at start | t 43 | — | materials |
## Materials replenishment: at rest today
| Scenario | Anchor | Er / Ed / Es t100 | renewables below floor | materials below floor | sinks below floor | lowest at t100 |
|---|---|---|---|---|---|---|
| Baseline (current trends) | B1 | 0.16 / 0.47 / 0.32 | below at start | — | — | renewables |
| Baseline (current trends) | B2 | 0.20 / 0.55 / 0.35 | below at start | — | — | renewables |
| Baseline (current trends) | B3 | 0.18 / 0.52 / 0.29 | below at start | — | — | renewables |
| Baseline (current trends) | B4 | 0.14 / 0.45 / 0.21 | below at start | — | — | renewables |
| Generative regime | B1 | 0.08 / 0.30 / 0.19 | below at start | — | t 83 | renewables |
| Generative regime | B2 | 0.08 / 0.29 / 0.17 | below at start | — | t 49 | renewables |
| Generative regime | B3 | 0.08 / 0.28 / 0.15 | below at start | — | t 37 | renewables |
| Generative regime | B4 | 0.08 / 0.29 / 0.14 | below at start | — | t 29 | renewables |
| Attention oligopoly | B1 | 0.25 / 0.62 / 0.43 | below at start | — | — | renewables |
| Attention oligopoly | B2 | 0.25 / 0.62 / 0.40 | below at start | — | — | renewables |
| Attention oligopoly | B3 | 0.21 / 0.56 / 0.32 | below at start | — | — | renewables |
| Attention oligopoly | B4 | 0.16 / 0.48 / 0.23 | below at start | — | — | renewables |
## Organism growth: class draw attributable to adoption speed (baseline, B4 − B1)
Relative change of each class between t 0 and t 50, B4 minus B1 (negative = organisms draw more).
| Materials replenishment | renewables | materials | sinks | order (most hit first) |
|---|---|---|---|---|
| none | -0.032 | -0.018 | -0.036 | sinks > renewables > materials |
| at rest | -0.032 | -0.018 | -0.036 | sinks > renewables > materials |

View file

@ -49,11 +49,17 @@ note § 1).
```task
id: ASSEMBLY-WP-0007-T02
status: todo
status: done
priority: medium
state_hub_task_id: "63efd39e-0366-5437-850b-503632e88a0a"
```
**Done 2026-10-13:** `gadm05.simulate_eco`, `eco_classes.py`, `models/GADM-0.5.md`
§ 2. Renewables are below the floor at the start. Sinks are the binding class
of the generative regime (t 29–83). Materials depend on replenishment. The
grounding test passed (sinks > renewables > materials). Low-carbon electricity
delays the sinks breach by 23–38 years.
Replace E with renewable flows, depletable stocks and sinks, each with its own
floor. Find which class binds first per scenario (scoping note § 2).