diff --git a/AGENTS.md b/AGENTS.md index f10c530..ce657ca 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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) ``` diff --git a/models/GADM-0.5.md b/models/GADM-0.5.md index 6a97c1b..fcf7789 100644 --- a/models/GADM-0.5.md +++ b/models/GADM-0.5.md @@ -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. diff --git a/models/ParameterGrounding.md b/models/ParameterGrounding.md index 954d1be..139df8a 100644 --- a/models/ParameterGrounding.md +++ b/models/ParameterGrounding.md @@ -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. diff --git a/simulations/gadm02/eco_classes.py b/simulations/gadm02/eco_classes.py new file mode 100644 index 0000000..097e67a --- /dev/null +++ b/simulations/gadm02/eco_classes.py @@ -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() diff --git a/simulations/gadm02/gadm05.py b/simulations/gadm02/gadm05.py index 8136cfe..7d019b6 100644 --- a/simulations/gadm02/gadm05.py +++ b/simulations/gadm02/gadm05.py @@ -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 diff --git a/simulations/gadm02/results/eco_classes.md b/simulations/gadm02/results/eco_classes.md new file mode 100644 index 0000000..94bb7c5 --- /dev/null +++ b/simulations/gadm02/results/eco_classes.md @@ -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 | diff --git a/workplans/ASSEMBLY-WP-0007-gadm-sectors-goods.md b/workplans/ASSEMBLY-WP-0007-gadm-sectors-goods.md index 57aa76f..1498212 100644 --- a/workplans/ASSEMBLY-WP-0007-gadm-sectors-goods.md +++ b/workplans/ASSEMBLY-WP-0007-gadm-sectors-goods.md @@ -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).