ASSEMBLY-WP-0007-T03: endogenous selection weights (capture slow; robust capture/de-capture; no material VFAC effect); T04 opened as two-good demand split
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:
parent
8dd9e97d33
commit
80055bc700
7 changed files with 261 additions and 2 deletions
|
|
@ -41,6 +41,7 @@ cd simulations/gadm02 && python3 -B world_scenarios.py # contexts X1–X4, hyp
|
|||
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 selection.py # GADM-0.5-dev endogenous selection weights
|
||||
cd simulations/gadm02 && python3 -B matching.py && python3 -B matching.py --imm # model matching; IMM flip-detection acceptance test (~6 min)
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -117,3 +117,51 @@ years.
|
|||
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.
|
||||
|
||||
## 3. Endogenous selection weights (T03)
|
||||
|
||||
`gadm05.simulate_sel`: the five selection weights (market, science,
|
||||
community, public, organism) relax at 0.05 per year toward targets pushed by
|
||||
domination and civic capacity:
|
||||
|
||||
- **Domination:** market concentration Pm raises the market weight, and
|
||||
discovery concentration Pd raises the organism weight (strength 2).
|
||||
- **Civic capacity:** epistemic capacity Q raises science, and commons X
|
||||
raise community (strength 1).
|
||||
|
||||
**Capture** is the share of selection weight held by the market and organism
|
||||
channels. Results are in `selection.py` and `results/selection.md`.
|
||||
|
||||
| Reading (endogenous − fixed weights, t 100) | B1 | B2 | B3 | B4 | class |
|
||||
|---|---|---|---|---|---|
|
||||
| capture, attention oligopoly | +0.114 | +0.131 | +0.138 | +0.141 | robust |
|
||||
| capture, baseline | +0.023 | +0.109 | +0.115 | +0.115 | quantitative shift |
|
||||
| capture, generative regime | −0.240 | −0.211 | −0.189 | −0.161 | robust |
|
||||
| ΔVFAC, any scenario | ≤ 0.002 in absolute value | | | | no effect |
|
||||
|
||||
Largest change in the weights themselves: 0.0044 per year.
|
||||
|
||||
Readings:
|
||||
|
||||
1. **Domination captures selection, and the generative regime de-captures
|
||||
it.** Both are robust across the band. Capture is slow and incremental, so
|
||||
the grounding test passes: no flip within a few years.
|
||||
2. **Capture of selection is not a material channel for VFAC in GADM.** The
|
||||
five quality signals are of similar size, so moving weight between them
|
||||
hardly changes selection quality σ. A plural selection mix also does not
|
||||
make the generative regime more stable against a domination shock.
|
||||
3. **What would make it material:** captured channels that deliver
|
||||
systematically worse quality. An example is organism selection under
|
||||
discovery concentration, `O = Q (1 − disc)`, which falls only through the
|
||||
lever `disc`, not through the discovery channel Pd. Linking O to Pd is the
|
||||
candidate change. It is recorded here and not implemented, because no
|
||||
reading depends on it yet.
|
||||
|
||||
## 4. Open: demand composition (T04, refined)
|
||||
|
||||
T01 found no genuine decoupling, because non-rival output only adds to rival
|
||||
consumption (BR-010). T02 locates the generative regime's ecological cost in
|
||||
the sinks. Both point to the same missing structure: a **two-good demand
|
||||
split**, rival and non-rival consumption, with substitution between them
|
||||
(dematerialization). This is narrower than the four-sector option in the scope
|
||||
note, and it is the question that opens T04.
|
||||
|
|
|
|||
|
|
@ -115,6 +115,11 @@ 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.
|
||||
|
||||
**T03 result (2026-10-13, `models/GADM-0.5.md` § 3):** test passed. The
|
||||
largest change in the selection weights is 0.0044 per year, so capture is slow
|
||||
and incremental. New priors to ground: the adjustment speed 0.05 per year and
|
||||
the strengths k_cap 2 and k_civ 1.
|
||||
|
||||
## 4. Remaining open grounding needs
|
||||
|
||||
1. Commons investment `IX`: needs a mapping concept, not just data.
|
||||
|
|
|
|||
|
|
@ -114,3 +114,58 @@ def simulate_eco(params: dict | None = None, init: dict | None = None, eco: dict
|
|||
else min(1.0, max(0.0, s[k] + dt * d[k]))) for k in STOCKS_ECO}
|
||||
s["E"] = eco_E(s)
|
||||
return rows
|
||||
|
||||
|
||||
# --- ASSEMBLY-WP-0007-T03: endogenous selection weights ----------------------------------------
|
||||
# Selection quality sigma mixes five channels (market M, science Q, community N(1-P), public S,
|
||||
# organism O) with weights wm, ws, wc, wp, wo. Here the weights are a slow state: each relaxes at
|
||||
# rate sel_lam toward a target pushed by domination (market concentration Pm raises the market
|
||||
# weight, discovery concentration Pd raises the organism weight) and by civic capacity (epistemic
|
||||
# capacity Q raises science, commons X raise community). Scope: GADM-Sectors-Scope.md § 4.
|
||||
SEL_PARAMS = {"sel_lam": 0.05, "k_cap": 2.0, "k_civ": 1.0}
|
||||
WEIGHTS = ("wm", "ws", "wc", "wp", "wo")
|
||||
|
||||
|
||||
def sel_targets(s: dict, w0: dict, s0: dict, q: dict) -> dict:
|
||||
return {"wm": w0["wm"] * max(0.0, 1 + q["k_cap"] * (s["Pm"] - s0["Pm"])),
|
||||
"wo": w0["wo"] * max(0.0, 1 + q["k_cap"] * (s["Pd"] - s0["Pd"])),
|
||||
"ws": w0["ws"] * max(0.0, 1 + q["k_civ"] * (s["Q"] - s0["Q"])),
|
||||
"wc": w0["wc"] * max(0.0, 1 + q["k_civ"] * (s["X"] - s0["X"])),
|
||||
"wp": w0["wp"]}
|
||||
|
||||
|
||||
def capture(w: dict, Ko: float) -> float:
|
||||
"""Share of selection weight held by market and organism channels."""
|
||||
wo = w["wo"] * Ko
|
||||
return (w["wm"] + wo) / (w["wm"] + w["ws"] + w["wc"] + w["wp"] + wo)
|
||||
|
||||
|
||||
def simulate_sel(params: dict | None = None, init: dict | None = None, sel: dict | None = None,
|
||||
endogenous: bool = True, T: float = 100.0, dt: float = 0.1, record_every: int = 10) -> list[dict]:
|
||||
"""GADM-0.5 with endogenous selection weights (fixed weights if endogenous=False)."""
|
||||
q = {**SEL_PARAMS, **(sel or {})}
|
||||
p = {**PARAMS, **(params or {})}
|
||||
s = {**g4.INIT, **(init or {})}
|
||||
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))}
|
||||
w0 = {k: p[k] for k in WEIGHTS}
|
||||
w = dict(w0)
|
||||
s0 = dict(s)
|
||||
rows = []
|
||||
steps = int(round(T / dt))
|
||||
for i in range(steps + 1):
|
||||
d, a = g4.derivatives(s, {**p, **w})
|
||||
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", "dem", "B", "V", "Vsel", "sigma")},
|
||||
**w, "capture": capture(w, s["Ko"])}
|
||||
row["VFAC"] = g4.g2.vfac(row)
|
||||
rows.append(row)
|
||||
if i < steps:
|
||||
if endogenous:
|
||||
tg = sel_targets(s, w0, s0, q)
|
||||
w = {k: max(0.0, w[k] + dt * q["sel_lam"] * (tg[k] - w[k])) for k in WEIGHTS}
|
||||
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 g4.STOCKS}
|
||||
return rows
|
||||
|
|
|
|||
41
simulations/gadm02/results/selection.md
Normal file
41
simulations/gadm02/results/selection.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# GADM-0.5-dev: endogenous selection weights across the band
|
||||
|
||||
Generated by `simulations/gadm02/selection.py` (ASSEMBLY-WP-0007-T03). Priors: weights relax at
|
||||
0.05/year; domination strength 2.0, civic strength 1.0. Capture = share of selection weight held by market + organism channels.
|
||||
Shock = {'Pd': 0.25, 'Pm': 0.15} added to the starting state. t = 100.
|
||||
|
||||
| Scenario | Anchor | VFAC fixed → endogenous | σ fixed → endogenous | capture t0 → t100 (fixed weights at t100) | max endogenous capture change/yr | shock VFAC loss fixed / endogenous |
|
||||
|---|---|---|---|---|---|---|
|
||||
| Baseline (current trends) | B1 | 0.411 → 0.411 | 0.418 → 0.426 | 0.42 → 0.45 (0.43) | 0.0021 | +0.003 / +0.003 |
|
||||
| Baseline (current trends) | B2 | 0.353 → 0.353 | 0.366 → 0.389 | 0.42 → 0.55 (0.44) | 0.0020 | -0.000 / -0.000 |
|
||||
| Baseline (current trends) | B3 | 0.337 → 0.337 | 0.326 → 0.341 | 0.42 → 0.60 (0.48) | 0.0023 | +0.000 / +0.000 |
|
||||
| Baseline (current trends) | B4 | 0.311 → 0.311 | 0.284 → 0.290 | 0.42 → 0.64 (0.53) | 0.0027 | +0.000 / +0.000 |
|
||||
| Attention oligopoly | B1 | 0.338 → 0.339 | 0.357 → 0.380 | 0.42 → 0.54 (0.42) | 0.0017 | +0.000 / +0.000 |
|
||||
| Attention oligopoly | B2 | 0.302 → 0.302 | 0.311 → 0.326 | 0.42 → 0.57 (0.44) | 0.0020 | +0.000 / +0.000 |
|
||||
| Attention oligopoly | B3 | 0.289 → 0.289 | 0.264 → 0.264 | 0.42 → 0.61 (0.47) | 0.0026 | +0.000 / -0.000 |
|
||||
| Attention oligopoly | B4 | 0.265 → 0.266 | 0.212 → 0.201 | 0.42 → 0.66 (0.52) | 0.0035 | +0.000 / -0.000 |
|
||||
| Generative regime, concentrated lineages | B1 | 0.528 → 0.529 | 0.530 → 0.465 | 0.42 → 0.17 (0.44) | 0.0041 | -0.001 / -0.000 |
|
||||
| Generative regime, concentrated lineages | B2 | 0.474 → 0.475 | 0.479 → 0.474 | 0.42 → 0.38 (0.47) | 0.0036 | -0.004 / -0.003 |
|
||||
| Generative regime, concentrated lineages | B3 | 0.426 → 0.426 | 0.439 → 0.455 | 0.42 → 0.48 (0.51) | 0.0031 | -0.000 / -0.000 |
|
||||
| Generative regime, concentrated lineages | B4 | 0.389 → 0.390 | 0.414 → 0.424 | 0.42 → 0.51 (0.55) | 0.0027 | -0.000 / -0.000 |
|
||||
| Generative regime | B1 | 0.685 → 0.685 | 0.660 → 0.690 | 0.42 → 0.23 (0.47) | 0.0044 | -0.000 / -0.000 |
|
||||
| Generative regime | B2 | 0.661 → 0.659 | 0.612 → 0.652 | 0.42 → 0.29 (0.50) | 0.0043 | -0.000 / -0.001 |
|
||||
| Generative regime | B3 | 0.641 → 0.639 | 0.579 → 0.618 | 0.42 → 0.34 (0.53) | 0.0040 | -0.000 / -0.001 |
|
||||
| Generative regime | B4 | 0.577 → 0.577 | 0.507 → 0.521 | 0.42 → 0.39 (0.55) | 0.0038 | -0.000 / -0.000 |
|
||||
|
||||
## Readings and robustness class
|
||||
|
||||
| Reading | B1 | B2 | B3 | B4 | class |
|
||||
|---|---|---|---|---|---|
|
||||
| endogenous capture at t100 (endogenous − fixed weights): Baseline (current trends) | +0.023 | +0.109 | +0.115 | +0.115 | quantitative shift |
|
||||
| ΔVFAC endogenous − fixed: Baseline (current trends) | +0.000 | +0.000 | -0.000 | -0.000 | QUALITATIVE BREAK |
|
||||
| endogenous capture at t100 (endogenous − fixed weights): Attention oligopoly | +0.114 | +0.131 | +0.138 | +0.141 | robust |
|
||||
| ΔVFAC endogenous − fixed: Attention oligopoly | +0.000 | +0.000 | +0.000 | +0.000 | quantitative shift |
|
||||
| endogenous capture at t100 (endogenous − fixed weights): Generative regime, concentrated lineages | -0.265 | -0.092 | -0.028 | -0.034 | quantitative shift |
|
||||
| ΔVFAC endogenous − fixed: Generative regime, concentrated lineages | +0.001 | +0.000 | -0.000 | +0.000 | QUALITATIVE BREAK |
|
||||
| endogenous capture at t100 (endogenous − fixed weights): Generative regime | -0.240 | -0.211 | -0.189 | -0.161 | robust |
|
||||
| ΔVFAC endogenous − fixed: Generative regime | -0.001 | -0.001 | -0.002 | -0.000 | quantitative shift |
|
||||
| shock loss difference (endogenous − fixed), generative regime | -0.000 | -0.000 | -0.000 | -0.000 | quantitative shift |
|
||||
|
||||
Largest change of the endogenous part of capture in any run: 0.0044 per year (slow and incremental; grounding test: no flip within a few years).
|
||||
Rows with ΔVFAC of ±0.000 are classified by sign noise; read them as 'no effect'.
|
||||
89
simulations/gadm02/selection.py
Normal file
89
simulations/gadm02/selection.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
"""Endogenous selection weights across the adoption band (ASSEMBLY-WP-0007-T03).
|
||||
|
||||
Tests (GADM-Sectors-Scope.md § 4; ParameterGrounding.md § 3):
|
||||
1. Does domination capture selection itself (market + organism weight share rising with P)?
|
||||
2. Is capture slow and incremental (no flip of the weights within a few years)?
|
||||
3. Does a plural selection mix make the generative regime more stable against a
|
||||
domination shock?
|
||||
|
||||
Usage: python3 -B simulations/gadm02/selection.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.dont_write_bytecode = True
|
||||
|
||||
import band_probe as bp # noqa: E402
|
||||
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)
|
||||
SCEN = ("baseline", "attention_oligopoly", "generative_concentrated_lineages", "generative_regime")
|
||||
SHOCK = {"Pd": 0.25, "Pm": 0.15} # domination shock added to the starting state
|
||||
|
||||
|
||||
def max_rate(en: list[dict], fx: list[dict]) -> float:
|
||||
"""Fastest change of the *endogenous part* of capture (endogenous minus fixed weights) per year.
|
||||
Capture itself also moves with K_Omega (organism weight x K_Omega), even with fixed weights."""
|
||||
diff = [(e["t"], e["capture"] - f["capture"]) for e, f in zip(en, fx)]
|
||||
return max(abs(b - a) / (tb - ta) for (ta, a), (tb, b) in zip(diff, diff[1:]))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
OUT.mkdir(exist_ok=True)
|
||||
scs = load_all()
|
||||
var = {a: gr.variant(gr.BAND[a]) for a in ANCHORS}
|
||||
res = {}
|
||||
for a in ANCHORS:
|
||||
for sc in SCEN:
|
||||
p = {**scs[sc]["params"], **var[a][0]}
|
||||
i0 = {**scs[sc]["init"], **var[a][1]}
|
||||
fx = g5.simulate_sel(p, i0, endogenous=False)
|
||||
en = g5.simulate_sel(p, i0, endogenous=True)
|
||||
shock = {k: min(1.0, i0.get(k, g5.g4.INIT[k]) + v) for k, v in SHOCK.items()}
|
||||
fxs = g5.simulate_sel(p, {**i0, **shock}, endogenous=False)
|
||||
ens = g5.simulate_sel(p, {**i0, **shock}, endogenous=True)
|
||||
res[(a, sc)] = {"Vfx": fx[-1]["VFAC"], "Ven": en[-1]["VFAC"], "c0": en[0]["capture"],
|
||||
"c100": en[-1]["capture"], "rate": max_rate(en, fx),
|
||||
"cfx100": fx[-1]["capture"],
|
||||
"loss_fx": fxs[-1]["VFAC"] - fx[-1]["VFAC"], "loss_en": ens[-1]["VFAC"] - en[-1]["VFAC"],
|
||||
"sig_fx": fx[-1]["sigma"], "sig_en": en[-1]["sigma"]}
|
||||
lines = ["# GADM-0.5-dev: endogenous selection weights across the band", "",
|
||||
"Generated by `simulations/gadm02/selection.py` (ASSEMBLY-WP-0007-T03). Priors: weights relax at",
|
||||
f"{g5.SEL_PARAMS['sel_lam']}/year; domination strength {g5.SEL_PARAMS['k_cap']}, civic strength "
|
||||
f"{g5.SEL_PARAMS['k_civ']}. Capture = share of selection weight held by market + organism channels.",
|
||||
f"Shock = {SHOCK} added to the starting state. t = 100.", "",
|
||||
"| Scenario | Anchor | VFAC fixed → endogenous | σ fixed → endogenous | capture t0 → t100 (fixed weights at t100) | max endogenous capture change/yr | shock VFAC loss fixed / endogenous |",
|
||||
"|---|---|---|---|---|---|---|"]
|
||||
for sc in SCEN:
|
||||
for a in ANCHORS:
|
||||
r = res[(a, sc)]
|
||||
lines.append(f"| {scs[sc]['title']} | {a} | {r['Vfx']:.3f} → {r['Ven']:.3f} | {r['sig_fx']:.3f} → "
|
||||
f"{r['sig_en']:.3f} | {r['c0']:.2f} → {r['c100']:.2f} ({r['cfx100']:.2f}) | {r['rate']:.4f} | "
|
||||
f"{r['loss_fx']:+.3f} / {r['loss_en']:+.3f} |")
|
||||
readings = []
|
||||
for sc in SCEN:
|
||||
readings.append((f"endogenous capture at t100 (endogenous − fixed weights): {scs[sc]['title']}",
|
||||
[res[(a, sc)]["c100"] - res[(a, sc)]["cfx100"] for a in ANCHORS]))
|
||||
readings.append((f"ΔVFAC endogenous − fixed: {scs[sc]['title']}", [res[(a, sc)]["Ven"] - res[(a, sc)]["Vfx"] for a in ANCHORS]))
|
||||
readings.append(("shock loss difference (endogenous − fixed), generative regime",
|
||||
[res[(a, 'generative_regime')]["loss_en"] - res[(a, 'generative_regime')]["loss_fx"] for a in ANCHORS]))
|
||||
lines += ["", "## Readings and robustness class", "", "| Reading | " + " | ".join(ANCHORS) + " | class |",
|
||||
"|---|" + "---|" * (len(ANCHORS) + 1)]
|
||||
for name, vals in readings:
|
||||
lines.append(f"| {name} | " + " | ".join(f"{v:+.3f}" for v in vals) + f" | {bp.classify(vals, 'sign')} |")
|
||||
rate = max(r["rate"] for r in res.values())
|
||||
lines += ["", f"Largest change of the endogenous part of capture in any run: {rate:.4f} per year "
|
||||
f"({'slow and incremental' if rate < 0.02 else 'FAST'}; grounding test: no flip within a few years).",
|
||||
"Rows with ΔVFAC of ±0.000 are classified by sign noise; read them as 'no effect'.", ""]
|
||||
(OUT / "selection.md").write_text("\n".join(lines))
|
||||
print("\n".join(lines))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -67,11 +67,16 @@ floor. Find which class binds first per scenario (scoping note § 2).
|
|||
|
||||
```task
|
||||
id: ASSEMBLY-WP-0007-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "e58601b5-ca84-59c5-8022-8dcfd084728a"
|
||||
```
|
||||
|
||||
**Done 2026-10-13:** `gadm05.simulate_sel`, `selection.py`, `models/GADM-0.5.md`
|
||||
§ 3. Domination captures selection (attention oligopoly +0.11 to +0.14), and
|
||||
the generative regime de-captures it (−0.16 to −0.24); both robust. Capture is
|
||||
slow (grounding test passed) and has no material effect on VFAC.
|
||||
|
||||
Make the selection-channel weights a slow state pushed by domination channels
|
||||
and governance levers. Test capture of selection (scoping note § 4).
|
||||
|
||||
|
|
@ -79,10 +84,25 @@ and governance levers. Test capture of selection (scoping note § 4).
|
|||
|
||||
```task
|
||||
id: ASSEMBLY-WP-0007-T04
|
||||
status: wait
|
||||
status: todo
|
||||
priority: low
|
||||
state_hub_task_id: "c3dbbe24-4378-55cf-91c1-9e2788646728"
|
||||
```
|
||||
|
||||
Only if T01–T03 raise a question that needs sector composition (scoping
|
||||
note § 3).
|
||||
|
||||
**Opened 2026-10-13, refined:** T01 and T02 raise one such question. Genuine
|
||||
decoupling needs non-rival consumption to *replace* rival consumption (BR-010),
|
||||
and the generative regime's ecological cost sits in the sinks. Implement a
|
||||
**two-good demand split**: rival and non-rival consumption with a substitution
|
||||
elasticity and a preference shift driven by non-rival quality (X, Q). Do not
|
||||
implement the full four-sector model. Tests:
|
||||
|
||||
1. Can VFAC rise while physical throughput falls, for reasons other than
|
||||
organism decline?
|
||||
2. Does the generative regime's sink breach move out of the 100-year
|
||||
horizon?
|
||||
|
||||
Ground the elasticity in dematerialization evidence, for example the material
|
||||
footprint per unit of GDP over time (Eurostat env_ac_rme, UNEP IRP).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue