diff --git a/.custodian-brief.md b/.custodian-brief.md index 2784301..e2f9f2a 100644 --- a/.custodian-brief.md +++ b/.custodian-brief.md @@ -2,16 +2,15 @@ # Custodian Brief — assembly-economics **Domain:** communication -**Last synced:** 2026-10-12 05:33 UTC +**Last synced:** 2026-10-12 05:35 UTC **State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)* ## Active Workstreams ### GADM-0.3: global sensitivity, power channels, cohorts -Progress: 4/6 done | workplan_id: `23e33ee7-cb27-52bc-819c-704f44f91663` +Progress: 5/6 done | workplan_id: `23e33ee7-cb27-52bc-819c-704f44f91663` **Open tasks:** -- · Strengthen attention dynamics and the full organism grid `f56e20b4` - · Life-cycle cohorts `2b749127` ## Inbox Hygiene diff --git a/AGENTS.md b/AGENTS.md index 04fa022..2d39e8e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,6 +23,7 @@ cd simulations/gadm02 && python3 gsa.py # global sensitivity, ~5 min cd simulations/gadm02 && python3 -B power_channels.py # GADM-0.3 power channels (T03 stage) cd simulations/gadm02 && python3 -B wealth.py # GADM-0.3 wealth vs. power cd simulations/gadm02 && python3 -B organism_grid.py # GADM-0.3 organism grid +cd simulations/gadm02 && python3 -B life_cycle.py # GADM-0.3 cohorts ``` Use `python3 -B` after quick edits; a stale bytecode cache once masked a change. diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md index dbfc919..b60a4df 100644 --- a/WORK-RECORDS.md +++ b/WORK-RECORDS.md @@ -44,5 +44,5 @@ | task | ASSEMBLY-WP-0005-T02 | done | — | workplans/ASSEMBLY-WP-0005-gadm-0.3.md | | task | ASSEMBLY-WP-0005-T03 | done | — | workplans/ASSEMBLY-WP-0005-gadm-0.3.md | | task | ASSEMBLY-WP-0005-T04 | done | — | workplans/ASSEMBLY-WP-0005-gadm-0.3.md | -| task | ASSEMBLY-WP-0005-T05 | todo | — | workplans/ASSEMBLY-WP-0005-gadm-0.3.md | +| task | ASSEMBLY-WP-0005-T05 | done | — | workplans/ASSEMBLY-WP-0005-gadm-0.3.md | | task | ASSEMBLY-WP-0005-T06 | todo | — | workplans/ASSEMBLY-WP-0005-gadm-0.3.md | diff --git a/models/GADM-0.3.md b/models/GADM-0.3.md index 484bf26..739479b 100644 --- a/models/GADM-0.3.md +++ b/models/GADM-0.3.md @@ -6,10 +6,10 @@ the code is the reference if the two ever disagree. # Generative Assembly Dynamics Model — GADM-0.3 -**Status:** in progress, exploratory. Implemented so far: power channels -(§ 2, ASSEMBLY-WP-0005-T03), wealth separated from power (§ 3, T04), -attention recalibration and the organism grid (§ 4, T05). Planned: cohorts -(T06). +**Status:** complete for ASSEMBLY-WP-0005, exploratory. Power channels +(§ 2, T03), wealth separated from power (§ 3, T04), attention recalibration +and organism grid (§ 4, T05), life-cycle cohorts (§ 5, T06). Open items are +in § 6 and ASSEMBLY-WP-0006. GADM-0.3 builds on GADM-0.2 (`GADM-0.2.md`). Everything not described here is unchanged; the implementation reuses `gadm02.py`. Time unit: one year. @@ -343,6 +343,106 @@ background reproduces the generative regime exactly (VFAC 0.672). stays at about 0.6, because it depends on discovery concentration, which is not an organism lever. +--- + +## 5. Life-cycle cohorts (T06) + +Implemented in `simulations/gadm02/gadm03c.py` on top of the full GADM-0.3. + +### 5.1 Structure + +| Cohort | Ages | Carries | Notes | +|---|---|---|---| +| children `ch` | 0–19 | H | education, adult attention as care input, seniors' mentoring | +| working age `w` | 20–64 | H, A | GADM-0.2 learning; deskilling; mentoring inflow T_g; main care provider | +| seniors `s` | 65–79 | H, A | half learning rate, 1.5× depreciation; provides a share of care | +| very old `d` | 80+ | H | 3× depreciation; main care need | + +Population counts follow births (`birth` × N_w) and ageing rates of 1/20, +1/45 and 1/15 per year, with deaths of the very old at 1/8 per year. At +`birth` = 1/45 (replacement), the age structure is stationary at about +23 / 51 / 17 / 9 %. A unit test checks this. + +Aggregates passed to the rest of the model: H is population-weighted over all +cohorts; A is weighted over working age and seniors. G remains a single +aggregate. + +Care need = 0.5 × share of children + 1.0 × share of very old. Its attention +cost is split between working age and seniors (`care_sen`), and reduced by +participation claims: relief = 1 − 3 × cp. + +### 5.2 Effect on the scenarios + +With cohorts, the baseline VFAC is 0.323 (0.334 without cohorts) and the +generative regime 0.656 (0.672). Capability and attention are a little lower, +because of senior depreciation and care load. The scenario ordering is +unchanged. + +### 5.3 Hypotheses L1–L3 + +Full tables: `simulations/gadm02/results/life_cycle.md`. + +**L1: strong intergenerational transfer lets an ageing society keep H. +Supported.** + +| Demography | T_g = 0 | T_g = 0.05 | T_g = 0.15 | +|---|---|---|---| +| stable (ΔH over 100 years) | −0.043 | −0.032 | −0.011 | +| ageing, births at 75 % of replacement | −0.053 | −0.040 | −0.018 | + +An ageing society with strong mentoring loses less capability than a stable +society without it. A first formulation of T_g, which transferred only +max(0, H_s − H_w), was inert because senior capability decays below +working-age capability. It was replaced by an inflow proportional to senior +capability and working-age headroom. + +**L2: without recognized care participation, A falls fastest in the +working-age cohort. Conditionally supported.** Attention is lowest in +whichever cohort carries the higher care load *per person*: + +- with seniors providing 10 % of care, working-age A is lowest (0.40 vs. 0.44); +- with 30 %, senior A is lowest (0.40 vs. 0.42), because there are fewer + seniors to share it. + +Care relief through participation claims (cp = 0.15) raises working-age +attention by 0.034–0.042 in every setting. So the post-work participation +channel directly protects the attention of carers. + +**L3: education reaches working-age capability with a 15–20 year lag. Not +supported in this model.** Raising education intensity by 50 % raises +children's capability by +0.067, but working-age capability only by +0.010, +with half of the effect reached after about 9 years. The cause is structural: +working-age capability relaxes to its own conditions within roughly 8 years +(adult learning and depreciation rates). That washes out the cohort inflow, +so H has almost no memory of childhood. Human-capital research generally +finds persistent effects of early education, so this points to a missing +mechanism, not an empirical result. The fix belongs in GADM-0.4: split H +into a durable, education-formed component and a current component. + +### 5.4 Further observations + +- **Ageing is slow in this demography.** At 75 % of replacement fertility, + the share of seniors and very old rises only from 0.26 to 0.29 in 100 years, + and total care need barely changes (fewer children offset more very old at + the chosen weights). +- **Aggregate H declines at baseline even with stationary demography** + (−0.043), because of senior and very-old depreciation, which the + single-population model did not have. + +--- + +## 6. Open items (handed to ASSEMBLY-WP-0006) + +- Split H into durable and current components (L3). +- Agency G per cohort. +- Initialise W and the cohort attention stocks at their own equilibria (§ 3.4 + reading 3, § 5.3 L2 note). +- Estimates instead of assumptions for the channel self-reinforcement r_k, the + wealth conversion k_w, and organism depreciation `dO` (the top driver in the + GADM-0.2 Sobol analysis). +- Global sensitivity analysis on GADM-0.3 (the Sobol run so far covers + GADM-0.2). + ## Reproduce ```bash @@ -350,4 +450,5 @@ python3 -B -m unittest discover -s simulations/gadm02 cd simulations/gadm02 && python3 -B power_channels.py # T03 stage (wealth off) cd simulations/gadm02 && python3 -B wealth.py # T04: P3 and scenarios cd simulations/gadm02 && python3 -B organism_grid.py # T05: 2 × 2 × 2 organism grid +cd simulations/gadm02 && python3 -B life_cycle.py # T06: cohorts, L1–L3 ``` diff --git a/models/README.md b/models/README.md index 0e7657d..2becddd 100644 --- a/models/README.md +++ b/models/README.md @@ -11,7 +11,7 @@ exploratory: they generate hypotheses and are not established results. | [InformationOrganismsInGADM.md](InformationOrganismsInGADM.md) | mapping note v0.1 | ASSEMBLY-WP-0003-T03; input for GADM-0.2 (ASSEMBLY-WP-0004) | | [GADM-CLD.md](GADM-CLD.md) | v0.1 | causal-loop diagram, loops, signed link table (ASSEMBLY-WP-0004-T01/T02) | | [GADM-0.2.md](GADM-0.2.md) | GADM-0.2 | extensions decision, equations, scenario and sensitivity findings (ASSEMBLY-WP-0004) | -| [GADM-0.3.md](GADM-0.3.md) | in progress | power channels (P1/P2) wealth separated from power (P3), attention recalibration and organism grid (ASSEMBLY-WP-0005-T03–T05) | +| [GADM-0.3.md](GADM-0.3.md) | GADM-0.3 | power channels (P1/P2) wealth separated from power (P3), attention recalibration, organism grid, life-cycle cohorts (ASSEMBLY-WP-0005) | | [GADM-0.3-Candidates.md](GADM-0.3-Candidates.md) | outline | life-cycle and power extensions, deferred items (ASSEMBLY-WP-0004-T08) | ## Conventions diff --git a/simulations/README.md b/simulations/README.md index 82cdde1..f116b84 100644 --- a/simulations/README.md +++ b/simulations/README.md @@ -6,7 +6,8 @@ model version it implements. | Directory | Model | Entry points | |-----------|-------|--------------| | `gadm02/` | GADM-0.2 (`models/GADM-0.2.md`) | `run_scenarios.py`, `sensitivity.py`, `gsa.py`, `test_gadm02.py` | -| `gadm02/gadm03.py` | GADM-0.3: power channels, wealth (`models/GADM-0.3.md`) | `power_channels.py`, `wealth.py`, `organism_grid.py`, `test_gadm03.py` | +| `gadm02/gadm03.py` | GADM-0.3: power channels, wealth, attention (`models/GADM-0.3.md`) | `power_channels.py`, `wealth.py`, `organism_grid.py`, `test_gadm03.py` | +| `gadm02/gadm03c.py` | GADM-0.3 with life-cycle cohorts (`models/GADM-0.3.md` § 5) | `life_cycle.py`, `test_gadm03c.py` | Python 3.10+, standard library only. Use `python3 -B` after quick edits: a stale bytecode cache can mask same-size changes made within the same second. diff --git a/simulations/gadm02/gadm03c.py b/simulations/gadm02/gadm03c.py new file mode 100644 index 0000000..1d2dd38 --- /dev/null +++ b/simulations/gadm02/gadm03c.py @@ -0,0 +1,141 @@ +"""GADM-0.3 with life-cycle cohorts (ASSEMBLY-WP-0005-T06). + +Extends gadm03 (power channels, wealth, recalibrated attention). Human +capability H and attention headroom A become cohort quantities; everything else +is unchanged and sees population-weighted aggregates: + + cohorts: ch (children, 0-19), w (working age, 20-64), + s (seniors, 65-79), d (very old / dependent, 80+) + +Population counts N_c evolve by births (b * N_w), ageing (1/20, 1/45, 1/15 per +year) and deaths of the very old (1/8 per year). With b = 1/45 the age +structure is stationary (shares ≈ 23 / 51 / 17 / 9 %). + +Intensive cohort quantities follow their own dynamics plus a mixing term when +people age in: dX_c += (inflow_c / N_c) * (X_from - X_c). + +Effective agency G stays a single aggregate in this version. + +Mentoring (T_g) is an inflow proportional to seniors' capability and +working-age headroom. A first version transferred only max(0, Hs - Hw); since +seniors' capability decays below working-age capability, that term was inert +(L1 showed zero effect) and was replaced. +""" + +from __future__ import annotations + +import gadm02 as g2 +import gadm03 as g3 + +MODEL_VERSION = "GADM-0.3-cohorts" +TIME_UNIT = g3.TIME_UNIT + +COHORTS = ("ch", "w", "s", "d") +AGE_RATE = {"ch": 1 / 20, "w": 1 / 45, "s": 1 / 15} +DEATH_D = 1 / 8 + +STOCKS = tuple(k for k in g3.STOCKS if k not in ("H", "A")) + ( + "Nch", "Nw", "Ns", "Nd", "Hch", "Hw", "Hs", "Hd", "Aw", "As") + +INIT = {k: v for k, v in g3.INIT.items() if k not in ("H", "A")} +INIT.update({ + # stationary age structure for b = 1/45 (shares of a population of 1) + "Nch": 0.2273, "Nw": 0.5114, "Ns": 0.1705, "Nd": 0.0909, + "Hch": 0.40, "Hw": 0.55, "Hs": 0.55, "Hd": 0.40, # aggregate H ≈ 0.50 + "Aw": 0.45, "As": 0.65, # aggregate adult A ≈ 0.50 +}) + +PARAMS = dict(g3.PARAMS) +PARAMS.update({ + "birth": 1 / 45, # births per working-age person per year (1/45 = replacement) + "edu": 1.0, # education intensity for children (multiplier) + "tg": 0.05, # intergenerational transfer: seniors' mentoring of working age + "tgc": 0.03, # seniors' mentoring of children + "dHs": 1.5, # capability depreciation multiplier, seniors + "dHd": 3.0, # capability depreciation multiplier, very old + "learn_s": 0.5, # learning multiplier for seniors + "care_load": 0.12, # attention cost of care per unit of care need + "care_sen": 0.3, # share of informal care provided by seniors + "care_relief": 3.0, # relief of informal care per unit of participation claims cp +}) + + +def shares(s: dict) -> dict: + tot = s["Nch"] + s["Nw"] + s["Ns"] + s["Nd"] + return {c: s["N" + c] / tot for c in COHORTS} + + +def aggregates(s: dict) -> dict: + n = shares(s) + H = sum(n[c] * s["H" + c] for c in COHORTS) + A = (n["w"] * s["Aw"] + n["s"] * s["As"]) / (n["w"] + n["s"]) + return {"H": H, "A": A, **{"n_" + c: n[c] for c in COHORTS}} + + +def derivatives(s: dict, p: dict) -> tuple[dict, dict]: + agg = aggregates(s) + base = {k: v for k, v in s.items() if k in g3.STOCKS} + base["H"], base["A"] = agg["H"], agg["A"] + d3, a = g3.derivatives(base, p) + d = {k: v for k, v in d3.items() if k not in ("H", "A")} + + S, B, X, Ko, m = s["S"], a["B"], s["X"], s["Ko"], p["m"] + n = shares(s) + Nch, Nw, Ns, Nd = s["Nch"], s["Nw"], s["Ns"], s["Nd"] + + # demography + births = p["birth"] * Nw + flow = {"ch": AGE_RATE["ch"] * Nch, "w": AGE_RATE["w"] * Nw, "s": AGE_RATE["s"] * Ns} + d["Nch"] = births - flow["ch"] + d["Nw"] = flow["ch"] - flow["w"] + d["Ns"] = flow["w"] - flow["s"] + d["Nd"] = flow["s"] - DEATH_D * Nd + + # human capability per cohort (GADM-0.2 form, cohort-specific modifiers) + social = p["h0"] * (0.5 * S + 0.5 * B) + desk = p["desk"] * Ko * (1 - m) + Hch, Hw, Hs, Hd = s["Hch"], s["Hw"], s["Hs"], s["Hd"] + d["Hch"] = (p["edu"] * (social + p["hT"] * X) + p["hA"] * s["Aw"] + p["tgc"] * n["s"] / max(n["ch"], 1e-9) * Hs) \ + * (1 - Hch) - p["dH"] * Hch + d["Hw"] = (social + p["hA"] * s["Aw"] + p["hT"] * X) * (1 - Hw) - (p["dH"] + desk) * Hw \ + + p["tg"] * n["s"] / max(n["w"], 1e-9) * Hs * (1 - Hw) \ + + flow["ch"] / Nw * (Hch - Hw) + d["Hs"] = p["learn_s"] * (social + p["hA"] * s["As"] + p["hT"] * X) * (1 - Hs) \ + - (p["dHs"] * p["dH"] + desk) * Hs + flow["w"] / Ns * (Hw - Hs) + d["Hd"] = -p["dHd"] * p["dH"] * Hd + flow["s"] / Nd * (Hs - Hd) + + # attention headroom: extraction (as GADM-0.3) plus informal care load + care_need = 0.5 * n["ch"] + 1.0 * n["d"] + relief = max(0.0, 1 - p["care_relief"] * p["cp"]) + load = p["care_load"] * care_need * relief + ext = p["aext"] * p["x_att"] * (0.2 + Ko) + rec = p["arec"] * (0.4 + 0.6 * B) + d["Aw"] = rec * (1 - s["Aw"]) - (ext + load * (1 - p["care_sen"]) / n["w"]) * s["Aw"] \ + + flow["ch"] / Nw * (0.5 - s["Aw"]) # young adults enter with A = 0.5 + d["As"] = rec * (1 - s["As"]) - (ext + load * p["care_sen"] / n["s"]) * s["As"] \ + + flow["w"] / Ns * (s["Aw"] - s["As"]) + a = {**a, **agg, "care_need": care_need} + return d, a + + +def simulate(params: dict | None = None, init: dict | None = None, + T: float = 100.0, dt: float = 0.1, record_every: int = 10) -> list[dict]: + p = {**PARAMS, **(params or {})} + s = {**INIT, **(init or {})} + unknown = set(p) - set(PARAMS) + if unknown: + raise KeyError(f"unknown parameters: {sorted(unknown)}") + rows = [] + steps = int(round(T / dt)) + for i in range(steps + 1): + d, a = derivatives(s, p) + if i % record_every == 0: + row = {"t": round(i * dt, 6), **s, "P": g3.total_p(s), + **{k: a[k] for k in ("H", "A", "n_ch", "n_w", "n_s", "n_d", "care_need", + "Ystar", "B", "V", "Vsel")}} + row["VFAC"] = 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} + return rows diff --git a/simulations/gadm02/life_cycle.py b/simulations/gadm02/life_cycle.py new file mode 100644 index 0000000..6ec277b --- /dev/null +++ b/simulations/gadm02/life_cycle.py @@ -0,0 +1,80 @@ +"""Life-cycle hypotheses L1-L3 for GADM-0.3 with cohorts (gadm03c). + +L1: strong intergenerational transfer T_g lets an ageing society keep H. +L2: care demand competes with attention; without recognized care participation + (C_p), attention headroom falls fastest in the working-age cohort. +L3: children's capability formation reaches working-age capability with a lag + of 15-20 years. + +Usage: python3 -B simulations/gadm02/life_cycle.py +""" + +from __future__ import annotations + +import sys +from pathlib import Path + +sys.dont_write_bytecode = True + +import gadm03c as c # noqa: E402 +from scenarios import load_all # noqa: E402 + +OUT = Path(__file__).resolve().parent / "results" +STABLE, AGEING = 1 / 45, 0.75 / 45 + + +def run(params: dict, base: dict) -> list[dict]: + return c.simulate({**base["params"], **params}, base["init"]) + + +def main() -> None: + OUT.mkdir(exist_ok=True) + sc = load_all()["baseline"] + lines = [f"# {c.MODEL_VERSION}: life-cycle hypotheses", "", + "Generated by `simulations/gadm02/life_cycle.py`. Baseline background,", + "t = 100 years. Ageing demography: births at 75 % of replacement.", ""] + + lines += ["## L1: intergenerational transfer in an ageing society", "", + "| Demography | T_g (tg) | seniors + very old (share, t=100) | H (t=0) | H (t=100) | ΔH |", + "|---|---|---|---|---|---|"] + for demo, b in (("stable", STABLE), ("ageing", AGEING)): + for tg in (0.0, 0.05, 0.15): + r = run({"birth": b, "tg": tg}, sc) + old = r[-1]["n_s"] + r[-1]["n_d"] + lines.append(f"| {demo} | {tg:.2f} | {old:.2f} | {r[0]['H']:.3f} | {r[-1]['H']:.3f} | " + f"{r[-1]['H'] - r[0]['H']:+.3f} |") + + lines += ["", "## L2: care load and attention", "", + "Levels at t = 100 are compared across settings (not against t = 0, because", + "initial cohort attention is not at its own equilibrium).", "", + "| Demography | care_sen (seniors' care share) | cp | A working age | A seniors | care load per working-age person | per senior |", + "|---|---|---|---|---|---|---|"] + for demo, b in (("stable", STABLE), ("ageing", AGEING)): + for cs in (0.1, 0.3): + for cp in (0.0, 0.15): + prm = {"birth": b, "cp": cp, "care_sen": cs} + r = run(prm, sc)[-1] + pp = {**c.PARAMS, **sc["params"], **prm} + load = pp["care_load"] * r["care_need"] * max(0.0, 1 - pp["care_relief"] * cp) + lines.append(f"| {demo} | {cs:.1f} | {cp:.2f} | {r['Aw']:.3f} | {r['As']:.3f} | " + f"{load * (1 - cs) / r['n_w']:.4f} | {load * cs / r['n_s']:.4f} |") + + lines += ["", "## L3: lag from education to working-age capability", "", + "Run difference: education intensity 1.5 vs. 1.0, everything else equal.", "", + "| t | ΔH children | ΔH working age | ΔH aggregate |", "|---|---|---|---|"] + lo, hi = run({"edu": 1.0}, sc), run({"edu": 1.5}, sc) + diffs = [(a["t"], b["Hch"] - a["Hch"], b["Hw"] - a["Hw"], b["H"] - a["H"]) for a, b in zip(lo, hi)] + for t, dc, dw, dh in diffs: + if t in (0, 5, 10, 15, 20, 25, 30, 40, 50, 75, 100): + lines.append(f"| {t:.0f} | {dc:+.3f} | {dw:+.3f} | {dh:+.3f} |") + final_w, final_c = diffs[-1][2], diffs[-1][1] + t_w = next(t for t, _dc, dw, _dh in diffs if dw >= 0.5 * final_w) + t_c = next(t for t, dc, _dw, _dh in diffs if dc >= 0.5 * final_c) + lines += ["", f"Half of the final effect is reached after {t_c:.0f} years for children and " + f"{t_w:.0f} years for working-age capability.", ""] + (OUT / "life_cycle.md").write_text("\n".join(lines)) + print("\n".join(lines)) + + +if __name__ == "__main__": + main() diff --git a/simulations/gadm02/results/life_cycle.md b/simulations/gadm02/results/life_cycle.md new file mode 100644 index 0000000..80e3f25 --- /dev/null +++ b/simulations/gadm02/results/life_cycle.md @@ -0,0 +1,51 @@ +# GADM-0.3-cohorts: life-cycle hypotheses + +Generated by `simulations/gadm02/life_cycle.py`. Baseline background, +t = 100 years. Ageing demography: births at 75 % of replacement. + +## L1: intergenerational transfer in an ageing society + +| Demography | T_g (tg) | seniors + very old (share, t=100) | H (t=0) | H (t=100) | ΔH | +|---|---|---|---|---|---| +| stable | 0.00 | 0.26 | 0.502 | 0.459 | -0.043 | +| stable | 0.05 | 0.26 | 0.502 | 0.470 | -0.032 | +| stable | 0.15 | 0.26 | 0.502 | 0.491 | -0.011 | +| ageing | 0.00 | 0.29 | 0.502 | 0.450 | -0.053 | +| ageing | 0.05 | 0.29 | 0.502 | 0.462 | -0.040 | +| ageing | 0.15 | 0.29 | 0.502 | 0.485 | -0.018 | + +## L2: care load and attention + +Levels at t = 100 are compared across settings (not against t = 0, because +initial cohort attention is not at its own equilibrium). + +| Demography | care_sen (seniors' care share) | cp | A working age | A seniors | care load per working-age person | per senior | +|---|---|---|---|---|---|---| +| stable | 0.1 | 0.00 | 0.399 | 0.438 | 0.0432 | 0.0144 | +| stable | 0.1 | 0.15 | 0.441 | 0.465 | 0.0238 | 0.0079 | +| stable | 0.3 | 0.00 | 0.417 | 0.395 | 0.0336 | 0.0432 | +| stable | 0.3 | 0.15 | 0.452 | 0.439 | 0.0185 | 0.0238 | +| ageing | 0.1 | 0.00 | 0.402 | 0.443 | 0.0407 | 0.0128 | +| ageing | 0.1 | 0.15 | 0.443 | 0.468 | 0.0224 | 0.0070 | +| ageing | 0.3 | 0.00 | 0.420 | 0.403 | 0.0317 | 0.0383 | +| ageing | 0.3 | 0.15 | 0.454 | 0.444 | 0.0174 | 0.0210 | + +## L3: lag from education to working-age capability + +Run difference: education intensity 1.5 vs. 1.0, everything else equal. + +| t | ΔH children | ΔH working age | ΔH aggregate | +|---|---|---|---| +| 0 | +0.000 | +0.000 | +0.000 | +| 5 | +0.053 | +0.003 | +0.013 | +| 10 | +0.067 | +0.006 | +0.018 | +| 15 | +0.069 | +0.008 | +0.020 | +| 20 | +0.069 | +0.008 | +0.020 | +| 25 | +0.068 | +0.009 | +0.020 | +| 30 | +0.068 | +0.009 | +0.020 | +| 40 | +0.067 | +0.009 | +0.020 | +| 50 | +0.067 | +0.009 | +0.020 | +| 75 | +0.067 | +0.010 | +0.021 | +| 100 | +0.067 | +0.010 | +0.021 | + +Half of the final effect is reached after 3 years for children and 9 years for working-age capability. diff --git a/simulations/gadm02/test_gadm03c.py b/simulations/gadm02/test_gadm03c.py new file mode 100644 index 0000000..7c69805 --- /dev/null +++ b/simulations/gadm02/test_gadm03c.py @@ -0,0 +1,44 @@ +"""Sanity tests for GADM-0.3 with cohorts. + +Usage: python3 -B -m unittest discover -s simulations/gadm02 +""" + +import unittest + +import gadm03c as c +from scenarios import load_all + + +class TestCohorts(unittest.TestCase): + def test_bounded_and_shares_sum_to_one(self): + for name, sc in load_all().items(): + for row in c.simulate(sc["params"], sc["init"]): + for k in c.STOCKS: + if not k.startswith("N"): + self.assertGreaterEqual(row[k], 0.0, (name, k)) + self.assertLessEqual(row[k], 1.0, (name, k)) + self.assertAlmostEqual(row["n_ch"] + row["n_w"] + row["n_s"] + row["n_d"], 1.0) + + def test_replacement_fertility_is_stationary(self): + r = c.simulate() + for k in ("n_ch", "n_w", "n_s", "n_d"): + self.assertAlmostEqual(r[0][k], r[-1][k], places=3, msg=k) + + def test_low_fertility_ages_the_population(self): + r = c.simulate({"birth": 0.75 / 45})[-1] + s = c.simulate()[-1] + self.assertGreater(r["n_s"] + r["n_d"], s["n_s"] + s["n_d"]) + + def test_mentoring_raises_capability(self): + lo = c.simulate({"tg": 0.0})[-1]["H"] + hi = c.simulate({"tg": 0.15})[-1]["H"] + self.assertGreater(hi, lo) + + def test_care_relief_raises_working_age_attention(self): + lo = c.simulate({"cp": 0.0})[-1]["Aw"] + hi = c.simulate({"cp": 0.15})[-1]["Aw"] + self.assertGreater(hi, lo) + + +if __name__ == "__main__": + unittest.main() diff --git a/workplans/ASSEMBLY-WP-0005-gadm-0.3.md b/workplans/ASSEMBLY-WP-0005-gadm-0.3.md index fd9473e..8e37468 100644 --- a/workplans/ASSEMBLY-WP-0005-gadm-0.3.md +++ b/workplans/ASSEMBLY-WP-0005-gadm-0.3.md @@ -4,7 +4,7 @@ type: workplan title: "GADM-0.3: global sensitivity, power channels, cohorts" domain: communication repo: assembly-economics -status: active +status: finished flavor: residual origin: residual origin_ref: ASSEMBLY-WP-0004 @@ -89,10 +89,32 @@ organism scenario grid (lineage × membrane × attention regime). ```task id: ASSEMBLY-WP-0005-T06 -status: todo +status: done priority: low state_hub_task_id: "2b749127-9f41-5bff-9a56-19ccd8fe9dd6" ``` Implement `GADM-0.3-Candidates.md` § 1: four cohorts, intergenerational transfer, and care demand on attention. Test hypotheses L1–L3. + +## Outcome + +All tasks are done. Results are in `models/GADM-0.3.md` and +`models/GADM-0.2.md` § 5.1. + +- T01: one period = one year; global sensitivity analysis. The model is + nearly additive. The "reuse as a bundle" reading was refuted, and organism + governance levers were confirmed as dominant. +- T02: literature verified; AI-growth prior art added; novelty claim 2 + narrowed. +- T03: six power channels. P1 is mostly unsupported, except lineage + hysteresis; P2 is supported. +- T04: wealth separated from power. P3 is supported and robust. +- T05: attention recalibrated against time-use data. In the 2 × 2 × 2 grid, + lineage ownership is the strongest organism lever. +- T06: life-cycle cohorts. L1 is supported (after fixing an inert mentoring + term), L2 is conditional, and L3 is not supported (a missing durable-capability + mechanism). + +Residual: ASSEMBLY-WP-0006 (GADM-0.4, proposed) carries the open items in +`GADM-0.3.md` § 6. diff --git a/workplans/ASSEMBLY-WP-0006-gadm-0.4.md b/workplans/ASSEMBLY-WP-0006-gadm-0.4.md new file mode 100644 index 0000000..45be6c9 --- /dev/null +++ b/workplans/ASSEMBLY-WP-0006-gadm-0.4.md @@ -0,0 +1,91 @@ +--- +id: ASSEMBLY-WP-0006 +type: workplan +title: "GADM-0.4: durable capability, cohort agency, estimated parameters" +domain: communication +repo: assembly-economics +status: proposed +flavor: residual +origin: residual +origin_ref: ASSEMBLY-WP-0005 +depends_on: [ASSEMBLY-WP-0005] +owner: claude-code +topic_slug: coulomb-social +created: "2026-10-12" +updated: "2026-10-12" +--- + +# GADM-0.4: durable capability, cohort agency, estimated parameters + +Residual of ASSEMBLY-WP-0005: the open items in `models/GADM-0.3.md` § 6, plus +the GADM-0.1 § 26 plan for GADM-0.4. Not to be started until it is promoted +to `ready`. + +## Split human capability into durable and current components + +```task +id: ASSEMBLY-WP-0006-T01 +status: todo +priority: high +``` + +L3 failed because H has no memory of childhood. Add a slowly depreciating, +education-formed component next to the current one, then re-test L3. + +## Ground key parameters + +```task +id: ASSEMBLY-WP-0006-T02 +status: todo +priority: high +``` + +Replace the assumed values of organism depreciation `dO` (the top Sobol +driver), channel self-reinforcement r_k and wealth conversion k_w with +literature- or data-based ranges. Re-run the affected readings. + +## Global sensitivity on GADM-0.3 + +```task +id: ASSEMBLY-WP-0006-T03 +status: todo +priority: medium +``` + +Extend `gsa.py` to the GADM-0.3 models (channels, wealth, cohorts). Check +whether the near-additivity of GADM-0.2 survives the superlinear channel +dynamics. + +## Equilibrium initialisation + +```task +id: ASSEMBLY-WP-0006-T04 +status: todo +priority: medium +``` + +Initialise W and the cohort attention stocks at their own equilibria, to +remove the initial-condition confounds noted in `GADM-0.3.md` §§ 3.4 and 5.3. + +## Agency per cohort + +```task +id: ASSEMBLY-WP-0006-T05 +status: todo +priority: low +``` + +Give G a cohort structure (restartability and exit options differ strongly +by age). + +## Sectors and rival goods + +```task +id: ASSEMBLY-WP-0006-T06 +status: todo +priority: low +``` + +GADM-0.1 § 26 plan for GADM-0.4: multiple sectors, rival versus non-rival +goods, ecological resource classes, institutional selection mechanisms. +Scope this into its own workplan before implementing it.