#1000 — Backfill founding_age_years for inhabited bodies
founding_age_years was NULL on all 273 inhabited bodies; it gates ConstructionEra (D-229) and block irregularity (D-216). Source-canonical fix: an idempotent MIGRATION_SQL UPDATE in import_economics.py + make regen-db. No hand-edit of systems.db.
Events-first:colonial_charter authored age (the real founding event — the named founding/first_settlement/colonization types match zero rows; civilizational_origin @ 12900yr correctly excluded).
## #1000 — Backfill founding_age_years for inhabited bodies
`founding_age_years` was NULL on all 273 inhabited bodies; it gates `ConstructionEra` (D-229) and block irregularity (D-216). Source-canonical fix: an idempotent `MIGRATION_SQL` UPDATE in `import_economics.py` + `make regen-db`. No hand-edit of `systems.db`.
### Derivation (per D-216 amendment)
`founding_age_years = COALESCE(colonial_charter event age_years, settlement_wave fallback)`
- **Events-first:** `colonial_charter` authored age (the real founding event — the named `founding`/`first_settlement`/`colonization` types match zero rows; `civilizational_origin` @ 12900yr correctly excluded).
- **Wave fallback:** wave_1=600, wave_2=500, wave_3=300, wave_4=100, wave_5=40.
- **Excluded** (stays NULL): `settlement_wave IN ('origin','unsettled')` — Sol is out of player scope (D-236).
### Result (QA-verified, Hoshe APPROVE — 7/7 checks pass)
- **269/273** inhabited bodies populated; **4** NULL = Sol bodies (Earth/Luna/Mars/Europa), correct.
- 11 charter-sourced bodies match authored ages exactly; 258 from wave fallback; 0 wave mismatches.
- Idempotent (`WHERE founding_age_years IS NULL`); range sane (40–600); `check-systems-db` stamp fresh.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Review: founding-age-backfill → main (code) — CHANGES REQUESTED
Reviewers: Hoshe (data QA), Tyre (pipeline integrity). Both REQUEST_CHANGES.
The data is numerically perfect — 273 inhabited bodies, 269 set / 4 NULL (all Sol/origin, correct per D-236), 11 charter-sourced bodies (charter age wins over wave in every divergent case), 258 wave-fallback with zero mismatches across all five waves, range 40–600, idempotent (WHERE founding_age_years IS NULL makes re-run a no-op), source-canonical (only import_economics.py + regen'd systems.db), stamp fresh. The MIGRATION_SQL placement is the sanctioned escape-hatch path and the system_history PK guarantees the wave subquery is single-row.
One blocker (a decision-record consistency fix) + two low suggestions:
The decision text is stale vs the implemented behavior. It states events-first matches event_type ∈ {founding, first_settlement, colonization} and is "currently empty in the live DB, scaffolding only." Both are false: the SQL correctly uses event_type = 'colonial_charter' (9 authored systems, 11 inhabited bodies, 5 diverging from wave fallback — e.g. GJ 144=580, GJ 338B=590, GJ 380=480). The SQL is correct; the decision record is wrong. Update the amendment to colonial_charter and the real counts so the load-bearing D-record matches the implementation.
Hoshe + Tyre
2
tooling/economy-db/import_economics.py:~383
LIMIT 1 on the colonial_charter subquery has no ORDER BY — non-deterministic if a system ever gets two charter rows (none today). Add ORDER BY sort_order ASC LIMIT 1 to make the pick explicit.
Tyre
3
tooling/economy-db/import_economics.py:~386
Wave-fallback CASE has no ELSE — a future wave_6 (which passes the EXISTS guard) would silently yield NULL. Add ELSE NULL -- unexpected wave marker, or a post-update assert counting founding_age_years IS NULL AND inhabited=1 in non-excluded scope.
Tyre
Recommend folding the D-216 doc fix into this branch so the decision record and its implementation merge together.
🤖 review via /pr-review
## Review: founding-age-backfill → main (code) — **CHANGES REQUESTED**
Reviewers: **Hoshe** (data QA), **Tyre** (pipeline integrity). Both REQUEST_CHANGES.
The data is **numerically perfect** — 273 inhabited bodies, 269 set / 4 NULL (all Sol/`origin`, correct per D-236), 11 charter-sourced bodies (charter age wins over wave in every divergent case), 258 wave-fallback with **zero mismatches** across all five waves, range 40–600, idempotent (`WHERE founding_age_years IS NULL` makes re-run a no-op), source-canonical (only `import_economics.py` + regen'd `systems.db`), stamp fresh. The MIGRATION_SQL placement is the sanctioned escape-hatch path and the `system_history` PK guarantees the wave subquery is single-row.
One blocker (a decision-record consistency fix) + two low suggestions:
| # | File | Issue | By |
|---|------|-------|----|
| 1 | `decisions/architecture.md` — D-216 amendment (~L1208) | **The decision text is stale vs the implemented behavior.** It states events-first matches `event_type ∈ {founding, first_settlement, colonization}` and is "currently empty in the live DB, scaffolding only." Both are false: the SQL correctly uses `event_type = 'colonial_charter'` (9 authored systems, 11 inhabited bodies, 5 diverging from wave fallback — e.g. GJ 144=580, GJ 338B=590, GJ 380=480). **The SQL is correct; the decision record is wrong.** Update the amendment to `colonial_charter` and the real counts so the load-bearing D-record matches the implementation. | Hoshe + Tyre |
| 2 | `tooling/economy-db/import_economics.py:~383` | `LIMIT 1` on the `colonial_charter` subquery has no `ORDER BY` — non-deterministic if a system ever gets two charter rows (none today). Add `ORDER BY sort_order ASC LIMIT 1` to make the pick explicit. | Tyre |
| 3 | `tooling/economy-db/import_economics.py:~386` | Wave-fallback `CASE` has no `ELSE` — a future `wave_6` (which passes the EXISTS guard) would silently yield NULL. Add `ELSE NULL -- unexpected wave` marker, or a post-update assert counting `founding_age_years IS NULL AND inhabited=1` in non-excluded scope. | Tyre |
Recommend folding the D-216 doc fix into this branch so the decision record and its implementation merge together.
🤖 review via /pr-review
- Update D-216 amendment text to match the implemented decision:
events-first uses event_type='colonial_charter' (9 systems, 11 bodies,
5 diverging from wave) — not the stale founding/first_settlement/
colonization scaffolding vocabulary.
- Add ORDER BY sort_order ASC to the colonial_charter subquery for a
deterministic pick if a system ever has two charter rows.
- Add explicit ELSE NULL to the wave-fallback CASE so an unexpected
settlement_wave leaves a trace instead of silently nulling.
Data unchanged: 269/273 set, 4 Sol NULL; stamp fresh.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both reviewers re-verified against the follow-up commit.
Hoshe (data QA): APPROVE — D-216 amendment now reads event_type = 'colonial_charter' with accurate counts (9 systems / 11 bodies / 5 diverging, with examples), stale "empty/scaffolding" claim gone; ORDER BY sort_order ASC + ELSE NULL present; counts unchanged (273 / 269 set / 4 Sol NULL), 0 charter mismatches, 0 wave mismatches; stamp fresh; source-canonical path only.
Tyre (pipeline): APPROVE — D-record now matches implementation; deterministic charter pick and explicit CASE fallthrough in place; import_economics meta stamp fresh (generated_at post-dates the source edit), source + DB committed together — no binary-merge-conflict risk. "Surgical patch, no scope creep. Ship it."
No remaining items. Clean to merge.
🤖 re-review via /pr-review
## Re-review (commit `9f4b1bf02`) — **APPROVED**
Both reviewers re-verified against the follow-up commit.
**Hoshe (data QA): APPROVE** — D-216 amendment now reads `event_type = 'colonial_charter'` with accurate counts (9 systems / 11 bodies / 5 diverging, with examples), stale "empty/scaffolding" claim gone; `ORDER BY sort_order ASC` + `ELSE NULL` present; counts unchanged (273 / 269 set / 4 Sol NULL), 0 charter mismatches, 0 wave mismatches; stamp fresh; source-canonical path only.
**Tyre (pipeline): APPROVE** — D-record now matches implementation; deterministic charter pick and explicit CASE fallthrough in place; `import_economics` meta stamp fresh (`generated_at` post-dates the source edit), source + DB committed together — no binary-merge-conflict risk. "Surgical patch, no scope creep. Ship it."
No remaining items. Clean to merge.
🤖 re-review via /pr-review
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
#1000 — Backfill founding_age_years for inhabited bodies
founding_age_yearswas NULL on all 273 inhabited bodies; it gatesConstructionEra(D-229) and block irregularity (D-216). Source-canonical fix: an idempotentMIGRATION_SQLUPDATE inimport_economics.py+make regen-db. No hand-edit ofsystems.db.Derivation (per D-216 amendment)
founding_age_years = COALESCE(colonial_charter event age_years, settlement_wave fallback)colonial_charterauthored age (the real founding event — the namedfounding/first_settlement/colonizationtypes match zero rows;civilizational_origin@ 12900yr correctly excluded).settlement_wave IN ('origin','unsettled')— Sol is out of player scope (D-236).Result (QA-verified, Hoshe APPROVE — 7/7 checks pass)
WHERE founding_age_years IS NULL); range sane (40–600);check-systems-dbstamp fresh.🤖 Generated with Claude Code
Review: founding-age-backfill → main (code) — CHANGES REQUESTED
Reviewers: Hoshe (data QA), Tyre (pipeline integrity). Both REQUEST_CHANGES.
The data is numerically perfect — 273 inhabited bodies, 269 set / 4 NULL (all Sol/
origin, correct per D-236), 11 charter-sourced bodies (charter age wins over wave in every divergent case), 258 wave-fallback with zero mismatches across all five waves, range 40–600, idempotent (WHERE founding_age_years IS NULLmakes re-run a no-op), source-canonical (onlyimport_economics.py+ regen'dsystems.db), stamp fresh. The MIGRATION_SQL placement is the sanctioned escape-hatch path and thesystem_historyPK guarantees the wave subquery is single-row.One blocker (a decision-record consistency fix) + two low suggestions:
decisions/architecture.md— D-216 amendment (~L1208)event_type ∈ {founding, first_settlement, colonization}and is "currently empty in the live DB, scaffolding only." Both are false: the SQL correctly usesevent_type = 'colonial_charter'(9 authored systems, 11 inhabited bodies, 5 diverging from wave fallback — e.g. GJ 144=580, GJ 338B=590, GJ 380=480). The SQL is correct; the decision record is wrong. Update the amendment tocolonial_charterand the real counts so the load-bearing D-record matches the implementation.tooling/economy-db/import_economics.py:~383LIMIT 1on thecolonial_chartersubquery has noORDER BY— non-deterministic if a system ever gets two charter rows (none today). AddORDER BY sort_order ASC LIMIT 1to make the pick explicit.tooling/economy-db/import_economics.py:~386CASEhas noELSE— a futurewave_6(which passes the EXISTS guard) would silently yield NULL. AddELSE NULL -- unexpected wavemarker, or a post-update assert countingfounding_age_years IS NULL AND inhabited=1in non-excluded scope.Recommend folding the D-216 doc fix into this branch so the decision record and its implementation merge together.
🤖 review via /pr-review
Re-review (commit
9f4b1bf02) — APPROVEDBoth reviewers re-verified against the follow-up commit.
Hoshe (data QA): APPROVE — D-216 amendment now reads
event_type = 'colonial_charter'with accurate counts (9 systems / 11 bodies / 5 diverging, with examples), stale "empty/scaffolding" claim gone;ORDER BY sort_order ASC+ELSE NULLpresent; counts unchanged (273 / 269 set / 4 Sol NULL), 0 charter mismatches, 0 wave mismatches; stamp fresh; source-canonical path only.Tyre (pipeline): APPROVE — D-record now matches implementation; deterministic charter pick and explicit CASE fallthrough in place;
import_economicsmeta stamp fresh (generated_atpost-dates the source edit), source + DB committed together — no binary-merge-conflict risk. "Surgical patch, no scope creep. Ship it."No remaining items. Clean to merge.
🤖 re-review via /pr-review
Pull request closed