The session now runs inside the clide IDE, which exposes its UI surface as a
`clide <subsystem> <verb>` CLI (observe + drive parity). Skill copied from the
clide project; documents `clide capabilities` as the authoritative discovery
command and the observe/drive verbs (editor/files/git/search/pane/ui/pql).
clide has the pql planning store wired in (Tickets + Decisions sidebar panels),
so the just-merged migration powers the IDE's planning UI.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tyre (architecture review):
- .gitattributes: `.pql/changelog/*.sql` matched nothing (files are one level
deeper at .pql/changelog/<table>/<YYYY-MM>.sql), so the union-merge driver never
applied — `git check-attr merge` returned `unspecified`. Fixed to
`.pql/changelog/**/*.sql`; now resolves to `merge: union` for monthly + schema
files. Restores the changelog's conflict-free merge guarantee.
- Migration scripts: the re-runnable ones (seed_tickets.py, add_workshop_provenance.py)
now derive the repo root from `git rev-parse --show-toplevel` instead of a hardcoded
/main path, so re-running from a worktree/clone targets the right checkout. The three
one-shot transforms (restructure_decisions, repath_references, retag_ticket_refs)
get a comment noting they're already-applied and unsafe to re-run (git mv on moved
sources) — keeping the path honest rather than implying re-runnability.
Hoshe approved (all QA checks passed). ruff clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completes the Phase 4 consumer cutover: adds Bash(pql) / Bash(pql *) to
.claude/settings.json so the pql workflow runs without prompts. Added manually by
the lead — the auto-mode classifier blocks an agent from self-widening wildcard Bash
permissions even via /update-config (a deliberate security boundary).
SR_DB_PATH and the Bash(tooling/db/*) allowlist stay until Phase 6 (rollback path).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Workshop -> decision provenance was prose-only. Adds a `decision_refs:` YAML
frontmatter list (the confirmed D-records each workshop-outcomes.md touches,
filtered against the governance decision set) to all 17 workshop outcomes; the two
that lacked frontmatter (commodity-catalog, system-economic-specialization) get a
minimal block. pql indexes the list and `SELECT fm.decision_refs` round-trips it, so
"which workshops touch D-NNN" is answerable via SELECT + filter or `pql search`.
decision_refs is a relevance signal (decisions a workshop discusses/produces), not a
strict authorship claim — historical bare refs aren't disambiguated. Generated wiki
read-only sections are left untouched.
Noted in pql-requirements #5: 1.6.2 has no working DSL operator for frontmatter
list-membership (`~`/`contains` error, `in` matches nothing), so membership queries
need a client-side filter for now.
Reproducible via tooling/pql-migrate/add_workshop_provenance.py (idempotent).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Repoints the kanban workflow skills from tooling/db/* to the pql CLI:
- /whats-next: milestone queries -> `pql ticket list --label phase:4 --unblocked`
(--unblocked does the dependency walk, collapsing the old milestone + per-ticket
deps + milestone_deps steps); WIP via `pql ticket list --status in_progress` (pql
doesn't enforce the limit — warn manually); refinement append via `pql ticket append`;
activation via `pql ticket status`.
- /ticket: full reference rewritten to `pql ticket`/`pql plan`; milestone subcommands
-> phase labels; points at .claude/rules/ticket-cli.md.
- /pr-process: step 8 extracts T-NNN (maps bare #NNN -> T-NNN) and calls
`pql ticket status T-<id> review`.
- /bug-report: bug creation via `pql ticket new bug`.
- clerk: decisions-sync mechanism line -> `pql decisions sync` (factual fix only; the
agent's review logic stays for the #965 re-enable).
- workshop-start IMPROVEMENTS: the old `decision claim` non-idempotency footgun no
longer applies — `pql decisions claim` is side-effect-free.
pr-review/git-commit needed only the Phase-1 path repoint (no command refs); the
settledreach.db.backup exclusion in pr-review stays until Phase 6.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rewrites the canonical command reference (.claude/rules/ticket-cli.md) and CLAUDE.md
to the pql CLI: `pql ticket`/`pql plan`/`pql decisions` replace `tooling/db/ticket`,
`sqlite-query`/`sqlite-exec`, and `tooling/db/decision`. Documents T-NNN ids, the
markdown-sourced governance decision tree, the rebuildable changelog-backed pql.db,
and labels-as-milestones (phase:4) in place of the removed milestone entity.
Maps the old surface accurately: ticket new (positional type+title), show
--with-context/--with-blockers, block --by / unblock --from, label add/remove,
decisions claim/list/show/validate/sync, plan whatsnext/review/status.
Behavioral/command cutover only — the legacy tooling/db/* and SR_DB_PATH stay as the
rollback path until Phase 6.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Folds pql's planning logic into the version-controlled .config/hooks/* (pql's own
.pql/hooks installer is dead under core.hooksPath=.config/hooks):
- pre-commit: + `pql decisions validate` (decision-ID/format gate, supersedes the
never-built check-decision-ids TODO) and `pql plan export --stage` (flush ticket
mutations to the git-tracked changelog and stage them into the commit). Both
guarded by `command -v pql`; export is a clean no-op when nothing changed.
- post-merge: `pql plan import` + `pql decisions sync` (replay incoming changelog,
re-sync markdown decisions).
- post-checkout (branch only): `pql plan rebuild` + `decisions sync`.
- post-rewrite (rebase/amend): `pql plan rebuild`.
- install-hooks chmods the three new hooks.
Makefile decision targets repointed to pql: decisions-sync -> `pql decisions sync`,
decisions-active -> `pql decisions list --type confirmed`, new decisions-validate ->
`pql decisions validate`. Dropped the SQLite-query conveniences (coverage/orphan/
orphan-tickets); per-decision coverage is `pql decisions show <id> --with-tickets`.
db-backup/db-install and SR_DB_PATH are intentionally kept until Phase 6 so the
legacy SQLite store stays intact as the migration rollback path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adopts the T-NNN convention (T-N == old #N == pql ticket id) across the active
operational layer: governance/ decision records, .claude/{rules,agents,skills},
CLAUDE.md, DECISIONS.md. 283 references rewritten.
Guarded against false positives (17 correctly skipped, each logged):
- PR references kept (PR #136/#138/... — PRs are a separate #-namespace)
- non-ticket numbers kept (#4122; the "#1 process failure" idiom; "task #3")
- only #N where N is an actual ticket id is rewritten; the 1-4 digit word-bounded
match also excludes 6-digit hex colours in the visual decision records
Git history is NOT rewritten (a commit's #N already equals T-N numerically), and
historical archives (docs/sprints, docs/discussions, docs/workshops) keep their
point-in-time #N. The /pr-process ticket-ID extraction logic moves to T-NNN in the
Phase 4 consumer cutover.
Verified: pql decisions validate ok; sync 357 records / 1057 refs / broken 0 (the
prose edits don't affect decision parsing or the tickets.decision_ref linkage).
Transform committed at tooling/pql-migrate/retag_ticket_refs.py.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
pql was developed off the lessons of this repo's own planning structures, so the
"requirements" are feedback to a descendant, not gaps in a foreign tool — and some
items are deliberate simplifications to adopt rather than ask pql to re-add.
- Item #1 (seeded ids) downgraded Critical -> Resolved: Phase 2 proved direct-INSERT
seeding + pql's max-id counter (inherited from our own CLI) mints T-1022 after
T-1021, so there is no recycling/collision. The --id flag is a low-priority nicety.
- Item #9 (milestones): pql's omission of the milestone entity validates our
vestigial finding; labels-as-milestones is the right call and we adopt it.
- Intro reframed around the lineage.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
One-way ticket data migration from the legacy settledreach.db into pql's
git-tracked changelog. Establishes the T-N == #N id bijection (old #440 -> T-440)
so thousands of #NNN git-commit references stay a trivial mapping.
Migrated (verified by full `pql plan rebuild` from changelog):
- 1013 tickets (status + type distributions match source exactly)
- 481 dependencies
- 16 history rows (deterministic content hash so ON CONFLICT(hash) dedups)
- 90 labels = 48 source + 42 milestone-derived
(active "Phase 4" milestone -> phase:4; "Process Rewire" ->
milestone:process-rewire; milestone_deps was empty/vestigial)
Transforms: ids T-prefixed, sprint_id dropped (legacy/archival), decision_ref
and the one 'server,client' comma-team (#575) kept verbatim, deleted_at NULL,
canonical_version 1. Seeded rows carry hash=NULL on tickets/deps/labels — proven
safe: PK-based ON CONFLICT, updated_at drives LWW, and replay is idempotent.
Key finding that dissolves pql-requirements item #1 ("Critical"): seeding via
direct-INSERT does NOT require explicit ticket ids from `ticket new`. The id
counter derives from max(id), so after seeding T-1..T-1021 the next native
`pql ticket new` mints T-1022 — no recycling, no collision. The blocker only
applied to the `ticket new --id` path we never use for bulk seeding.
Scaffolding: .pql/changelog/<table>/0000-schema.sql (canonical pql 1.6.2 schema,
byte-identical across the 4 table dirs) + .gitattributes union-merge driver so
changelog SQL never produces binary-style merge conflicts. Seed is reproducible
via tooling/pql-migrate/seed_tickets.py (read-only on the source, idempotent).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 1 follow-up: update the active instruction layer (CLAUDE.md, project
structure rule, DECISIONS.md redirect, agent personalities, skill docs) to
reference governance/{decisions,questions,rejected}/<domain>.md instead of the
retired flat decisions/*.md layout.
Path references only — command-surface references (tooling/db/decision*,
decisions-sync, Makefile targets, clerk) are repointed to the pql CLI in the
Phase 4 consumer cutover. Historical archives (docs/sprints, docs/discussions,
docs/workshops) keep their point-in-time decisions/ paths; the separate
whatsinagame/ template distribution is untouched. Agent-memory is gitignored
and out of scope.
The agent/skill repath was applied by tooling/pql-migrate/repath_references.py
(ordered, meaning-preserving replacements; bare-dir rule uses a negative
lookbehind so it can't corrupt a freshly-created governance/decisions/ path),
committed for provenance. CLAUDE.md, project-structure.md, and DECISIONS.md
were hand-edited (structural tree/table changes).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 1 of the pql migration. Moves the flat decisions/*.md layout into
governance/{decisions,questions,rejected}/<domain>.md — the tree pql's
`decisions sync` parses natively (record type from subdir, domain from
filename stem). Proven against pql 1.6.2: sync reports 357 records
(237 D / 108 Q / 12 R), 1057 refs, broken: 0; validate ok.
- 6 D-domain files -> governance/decisions/ (git renames)
- 5 questions-<domain>.md -> governance/questions/<domain>.md (prefix dropped)
- rejected.md split by domain -> governance/rejected/{architecture(R-001..010),
economics(R-011),perception(R-012)}.md
- decisions/README.md + questions.md index folded into governance/README.md;
pql's `decisions sync` now auto-maintains the record index appended below
the hand-written domain guidance (no more manual ID-list table upkeep).
- .pql/config.yaml: canonical vault config (tracked, not ignored).
Link rewrites are token-preserving: only the relative `foo.md` path portion
changes (e.g. `rejected.md#r-011` -> `../rejected/economics.md#r-011`); every
`[D-NNN]` bracket text and `#anchor` stays byte-identical, so pql's reference
extraction is unaffected. The one-shot transform is committed at
tooling/pql-migrate/restructure_decisions.py for provenance.
Codebase path references to decisions/ (CLAUDE.md, rules, skills, docs) are
updated in a follow-up commit.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 0 of the pql migration: the decision markdown had two genuine
canonical-ID integrity bugs that pql decisions sync silently LWW-collapses.
- D-035 was defined twice: a content.md tag-taxonomy record and a
perception.md shadowcasting/LOS record, both dated the same day. The
tag-taxonomy record keeps D-035; the shadowcasting record is renumbered
to D-238 (freshly claimed) with a Renumbered note preserving the history.
Inbound refs repointed in architecture.md (x4), questions-architecture.md,
and the README perception index row.
- R-011 (single currency for Phase 2) was defined three times: once
canonically in rejected.md and twice identically in economics.md. The two
economics.md copies are removed; rejected.md absorbs the Proposal/Raised-by
lines and gains a dedupe note. The economics.md dissent link now points at
rejected.md and the footer count drops the rejected-alternative clause.
Verified: tooling/db/decision check-dupes reports 0 duplicates;
pql decisions validate returns ok.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The blanket `.pql/` ignore would have hidden `.pql/changelog/` — pql's durable,
git-versioned planning state — making the whole migration's output invisible to
git. Narrow to ignore only the rebuildable DBs (index/pql .db + WAL/SHM) and
track config.yaml + changelog/.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deep analysis of migrating decisions + ticketing from the SQLite CLI to pql:
- pql-migration.md: phased branch-only plan (decisions→DQR tree, ticket changelog
seed with T-N≡#N, #N→T-N find-replace, big-bang consumer cutover, docs/workshops/
wiki fold-in, SQLite retirement) + verification gate + benefits.
- pql-requirements.md: 9 surfaced gaps for the pql team (critical: seeded ticket
ids + counter-advance; high: dup-id detection, core.hooksPath awareness, changelog
seed-format docs).
Key finding: milestones are vestigial (milestone_deps empty, 42/1013 tickets
linked) → mapped to a label, dropped as an entity.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PR #153 review (Hoshe H1): zone_type/era/floors/flavor all shared one fp_chain
and each took splitmix64(seed) of the same value, correlating the fields (era
tracking floor height across a city). Derive a distinct sub-chain per field so
they draw independent entropy. Block_tags aren't serialized, so no fixture
change; behavior stays deterministic.
Also (review): n=1 corridor test (empty, no panic), Frontier-density waterfront
test, and a comment on the reserved `_morphology` param (Tyre).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Note the #957 implementation on D-234: typed AccessPoint/CorridorSpine/
ChunkLayout, morphology-gated arterials + per-block lattice, BSP footprint
subdivision with D-233 coverage, and the waterfront rule. Flag the remaining
cross-layer dependency: the waterfront rule's real input (per-settlement Coastal
orientation) needs the Layer-3 placement -> Layer-4 GenerateSkeleton dispatch,
since city_context_reader still stubs founding_orientation to Cardinal.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Close the last D-234 piece — terrain water-direction extraction wired through
to founding orientation and the quarter waterfront rule:
- Layer 1: TerrainAnalysis::water_bearing — 8-octant integer bearing toward the
nearest water from the water_dist gradient (D-010, no atan2). Stored on
GeographicAttractor.water_bearing (360 = none).
- #956 founding orientation: coastal/river settlements now get a real
water-facing bearing (the anchoring attractor's), replacing the 0 stub.
- #957 waterfront rule (D-234b): the water-facing quarter edge (from the
settlement's Coastal founding orientation) drops its block setback to 0 so
buildings present flush to the quay (dock-orthogonal). Typed Edge + coastal_edge
+ per-block gating.
Golden + atlas_response fixture rebaked (additive water_bearing field only).
8 new tests. All integer-deterministic (D-010).
Pending: the waterfront rule reads context.founding_orientation, which
city_context_reader still stubs to Cardinal — real per-settlement orientation
reaches quarter generation once the Layer-3 placement -> Layer-4 GenerateSkeleton
dispatch is wired (the remaining cross-layer integration).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Complete the Layer-4 quarter geometry with the street layer (D-234), replacing
the ChunkLayout/CorridorSpine/AccessPoint String stubs with real types:
- AccessPoint{position,kind} + AccessKind (QuarterEdge/ReservationGate/
BlockJunction): the quarter's road nodes (from road_entry_directions octants +
reservation gates), the node set the D-097 audit reads.
- CorridorSpine{from,to,path}: arterial trunk edges, ±45°-snapped polylines
(D-096 cap). Topology gated by morphology (D-234a): Ribbon (fjord/canyon/
mountain-pass), HubSpoke (delta/island/enclosed water), Mesh/Prim-MST
(plains/meander/coastal). A spanning tree over the access nodes.
- ChunkLayout{spacing,offset,rotation_steps}: per-block local ±45° lattice,
spacing from density, offset/rotation modulated by the D-096 Grid/Organic mode.
Wired into generate_quarter_skeleton (access_points + corridors + per-block
chunk_layout). All integer-deterministic (D-010). 7 new tests.
Remaining D-234 piece: the per-edge waterfront pier/quay rule needs Layer-1
terrain water-adjacency threaded to the skeleton (cross-layer plumbing).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Build the per-quarter building geometry + tags (absorbs #976's footprint
subdivision into #957 — one coherent walkable-quarter deliverable):
- subdivide_block_footprints: deterministic BSP of each 128x128-tile block into
variable axis-aligned building plots (D-229 fast-path). Lot size + setback
scale with D-220 density (Frontier -> few big lots/wide gaps; Compressed ->
many small lots/shared walls); the D-233 BulkClass roofed-coverage fraction
decides building-vs-interstitial. morphology is wired in for the D-234
waterfront/street layer (needs Layer-1 terrain water-adjacency threaded up).
- assign_all_block_tags: subdivides + tags every non-reserved block's footprints
via the #957 derivation helpers, populating QuarterWorldState.block_tags in the
GenerateSkeleton plan-phase (D-230). Reserved blocks get no standard fill.
- Remove the write-only BlockSkeleton.era String stub - construction era now
lives per-footprint on BuildingPropertyTag.era (typed ConstructionEra).
All integer-deterministic (D-010). 5 new tests. Doors stay Vec::new() (#979).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Record the (ZoningType × economic_role × setting) → ZoneTypeId selection table
for the planetary cascade: base candidate slices per ZoningType refined by
economic_role, a setting tweaker (Maritime/Agricultural/Wilderness — planetary
variants only), and the gap-fill rules (entry-class U-curve at the D-217 Broken
band <2300bps; era per founding_age+prosperity+seed; FloorExtent from D-220
density midpoints; doors deferred to #979). Station-only zone ids are excluded —
they belong to a separate cascade (Q-109).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The pure per-footprint tag derivations for Layer-4 quarter generation (D-229),
ahead of the footprint-subdivision + assembly step:
- zone_type_for: the authored (ZoningType × economic_role × setting) → ZoneTypeId
selection (D-229 amendment) — planetary variants only, setting as a tweaker,
station-only ids never selected (Q-109); deterministic seed-pick, no empty slice.
- building_entry_class: zone × layout_mode × prosperity, with the D-217 Broken-band
U-curve degrade (Commercial→BreachOnly) and the Grid/Organic credential fork.
- construction_era: founding_age + prosperity + seed (D-229); old+Broken → Derelict.
- floor_extent: D-220 density-class floor ranges from density_pct + seed-jitter.
- initial_condition: D-217 frozen-amber condition from prosperity + era cause.
All integer-deterministic (D-010). 9 unit tests incl. the no-station-ids invariant.
Footprint subdivision + assign_building_tags assembly + block_tags wiring follow
(needs the footprint-packing model decided).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Surfaced during #957 zone-selection authoring: a body's setting/mode should
dispatch the cascade entry to planetary / station / mod-DLC-forked /
save-only(player_base) sources, distinct from setting's in-path tweaker role.
Captured as an open question so #957 stays scoped to the planetary path; this is
why #957's zone table excludes station-only zone ids.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PR #152 review (Hoshe): the faction→TerritorialStatus mapping test covered 7 of
the 8 D-237 values; add the missing "mixed" assertion (grouped with "disputed",
behavior already correct).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- D-212: add the AutonomistHeld variant (Compact of Westphalia) and record the
dominant_faction → TerritorialStatus mapping used in place of the
numeric faction-influence thresholds (which aren't in the data). Grounded in
wiki/factions/. IndigenousHeld/Derelict noted as deferred.
- D-214: note the political_archetype derivation + per-settlement storage.
- D-215: note the ArrangementPattern enum + derivation land here; block-adjacency
enforcement stays with the Quarter-skeleton generator (#957).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DrainageBasin gained a territorial_status field, so the Layer-1 golden and the
atlas_response msgpack fixture pick it up. Both changes are additive/
representational — basin/attractor/river selection is unchanged.
- cascade_golden.rs: pass None dominant_faction; golden rebaked (only
"territorial_status": "FrontierUnclaimed" added per basin).
- gen_fixtures.rs: set the new field in the atlas_response generator; fixture
regenerated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Derive and store each placed settlement's spatial character on top of the
#955 placement (D-212/213/214/215). Derivation is pure + integer-deterministic
(D-010); the cascade stays DB-free (D-225) — the enqueuer pre-resolves the
body's system faction onto the work item, like #955's settlements.
- TerritorialStatus (D-212): mapped from the authored dominant_faction
(territorial_status_from_faction). Adds an AutonomistHeld variant for the
Compact of Westphalia (self-governing bloc that rejects Assembly authority —
neither Commission, Corp, Contested, nor truly Frontier). Grounded in
wiki/factions/. Stored per-province on DrainageBasin.territorial_status
(uniform per body for now; forward-compatible for per-province faction data).
- PoliticalArchetype (D-214): political_archetype(status, role), status takes
precedence over economic_role.
- ArrangementPattern (D-215): new 5-variant enum + arrangement_pattern(); the
block-adjacency *enforcement* stays deferred to the Quarter-skeleton gen (#957)
— this only derives + stores which pattern applies.
- FoundingOrientation (D-213): existing fn extended with a seed-derived Free
bearing so pioneer/open-terrain grids vary per seed.
Wiring: dominant_faction threaded through CityContextReader
(read_body_dominant_faction) → atlas proxy (cache-miss read) → AnalyzeBody work
item → run_cascade → run_layer3/match_cities. Enrichment stored on CityPlacement
(political_archetype, arrangement_pattern, founding_orientation).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PR #151 review (Hoshe/Tyre): four doc comments in gen_queue.rs still said
"district" next to the renamed quarter_id field / generate_quarter_skeleton.
Pure comment update, no code change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
D-222 renamed the 512m generation cell from District to Quarter (District
is now a new 2048m tier above it). Align the generation skeleton code to
the canonical vocabulary. Pure naming — no behavior change; all 1296 lib
tests + integration tests pass unchanged.
Renamed (spatial-cell identifiers):
- DistrictSkeleton → QuarterSkeleton, DistrictWorldState → QuarterWorldState
- DistrictId → QuarterId, DistrictContext/DistrictBoundaries → Quarter*
- field district_id → quarter_id, district_type → quarter_type
- BodyWorldState.districts map → .quarters
- generate_skeleton → generate_quarter_skeleton
Deliberately left as-is (these name functional ZONING, not the spatial
tier — orthogonal to D-222): DistrictType, DistrictLayoutMode, the
district_mix module (DistrictMix/compute_district_mix), and the
GenWorkItem::GenerateSkeleton / GenCompletion::SkeletonGenerated variants.
Also aligned the perception "sim tile" → "subtile" vocabulary (D-222:
Subtile = 0.5m) in decisions/perception.md and the generation-cascade code
comments. Historical D-066/D-094/D-201/D-220 decision bodies keep their
existing D-222 amendment notes (not rewritten in place); the public
max_offset_sim_tiles fn name is unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per-machine tool dirs (.clide/settings.yaml, .pql/pql.db) that appeared as
untracked noise; not shared, should never be committed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The doctest imported `server::bps::log10_floor`, but the library crate is
`settled_reach_server` — so `cargo test --doc` failed to compile the
example (unresolved module `server`). Broken since the helper landed in
#145; it only surfaces under `--doc`, not `--lib`, so the pre-push gate
(which runs `--lib`) never caught it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address the doc/test-correctness items from PR #149 review:
- cascade.rs: Layer 3 is RNG-free (pure fn of attractors+cities); it does
not consume the carried SeedChain. Corrected the "first RNG-using layer"
claims on the module doc and the Settlement variant (Hoshe H3).
- cascade.rs: layers_are_ordered now also asserts Topography < Settlement,
pinning the invariant the up_to >= Settlement guards rely on (Tyre T2).
- features.rs: strength is an integer 0-100 (quantized at extraction), not
f32, and consumers that rank by it use the integer value (Hoshe H2).
- layer_proxy.rs: AtlasLayerRequest.up_to is not yet honored — run_work_item
runs through Settlement unconditionally; per-request depth deferred to
#1021 (Tyre T1).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
read_body_settlements propagated a parse error for any non-NULL but
unrecognized settlement_class, which the atlas proxy swallowed and then
enqueued the body with zero cities — one malformed row silently dropped
placement for the entire body. Treat an unknown variant like NULL: fall
back to PopulationBudget with a warning. parse_settlement_class stays
strict for the D-199 read_set path, which must abort on bad fields.
Found in PR #149 review (Hoshe H1). Adds a test covering the fallback.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mark Layer-3 settlement placement (#955) as running in-game now that the
B/E/F plumbing (per-body settlement read → work item → cache-miss proxy)
is wired.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wire the existing D-211 attractor-matching engine into the live
generation cascade so settlements are placed in-game, not just in tests.
- CityContextReader::read_body_settlements reads a body's settlements
from atlas_city_names (ordered by id for determinism). NULL
settlement_class defaults to PopulationBudget, not NameLocked: the
class is NULL until placement runs, and NameLocked would force every
settlement Tier-A in match_cities and collapse population tiering
(D-211). NULL economic_role falls back to residential.
- The AnalyzeBody work item carries the body's Vec<CityRecord>, and
run_work_item now runs up_to Settlement (was Topography). A body with
no settlements yields empty placements at negligible cost.
- The atlas layer proxy reads settlements on a cache miss and pins them
onto the work item, keeping the Rayon task DB-free (D-225). A read
failure is non-fatal: log and place no cities (Layer 1 still runs).
Threaded through a new CityContextReaderResource Bevy resource opened
in main.rs, mirroring BodySourceResolverResource.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
all_fixtures_deserialize panicked with "unknown fixture naming
convention: atlas_response_ready" — the test reads every .msgpack in
client/tests/fixtures/msgpack but had no branch for the atlas_response
prefix (the AtlasLayerResponse fixtures gen_fixtures emits, #969). A
pre-existing gap (present on main; the suite isn't gated by the pre-push
hook, which runs cargo-deny/ruff/JSON/stamp, not cargo test).
Add an atlas_response branch deserializing AtlasLayerResponse, and
regenerate atlas_response_ready.msgpack so its bytes match the now-integer
GeographicAttractor types (#955).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wire the existing attractor-matching engine (#919/#925) into the
generation cascade as Layer 3, and make the whole placement-scoring path
integer-deterministic.
Layer 3 (D-211):
- CascadeLayer::Settlement + Layer3Output (placements) on the snapshot;
BodyWorldState gains a `placements` field (the D-203 hot cache).
- run_layer3 runs the five-phase match_cities against Layer-1 attractors
via the authored D-195 compatibility matrix; pure function of
(attractors, cities) — no RNG. cities are passed in by the caller so the
cascade stays DB-free and testable. A `// cache seam` marks where a
persistent cache wraps it later (#1021).
- gen_queue passes &[] for now (Topography needs no cities); the runtime
settlement read (gen_queue/layer_proxy) is the #955 follow-on.
Integer determinism (D-010 / D-227 — D-195 amended):
- Wiring match_cities into the deterministic cascade made its f32 scoring
a live cross-platform divergence risk (a near-tie comparison or the
Hungarian's f32 reductions can round differently per platform → a
different world from the same seed). Converted the entire path to
integers: CompatibilityMatrix is a 0-100 affinity table; attractor
strength is 0-100 and terrain cost is a percent (100 = baseline),
quantized once at the Layer-1 feature boundary; cell_score, the
Hungarian, and CityPlacement.score are i64. No f32 in any placement or
ranking decision.
- Layer-1 golden fixture rebaked: confirmed selection/positions are
unchanged (same 256 attractors, 93 river cells) — only the strength/cost
representation changed.
Tests: lib green (1292); new settlement_layer_places_cities_deterministically
covers placement + determinism + propagation into BodyWorldState.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review fixes (Hoshe/Tyre, both APPROVE):
- populate_trait_templates / populate_atlas_body_trait_bias: the table
DELETEs ran unconditionally (safe only via transaction rollback on
dry-run, and divergent from every other populate_* function). Restructured
so validation + guardrails always run (dry-run now actually surfaces the
would-bake counts and catches errors) but mutations happen only under
`if not dry_run:`. Verified: --dry-run reports 28 templates, writes nothing.
- atlas_body_trait_bias: reject `pin` entries that carry a
weight_multiplier_bps (pin is mandatory, no multiplier) — closes a silent-
accept gap before #1017 authors ~30-40 real pins.
Deferred (noted on tickets): visual_bundle fallback-map completeness
(Phase-5/Araminta), pin-count-vs-K bake check (#1017 acceptance),
geographic_sector pool-narrowing semantics (#977).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The D-232 core hand-curated catalog (28 templates) the architecture-flavor
draw reads from, baked into trait_templates (#993):
- Cross-corridor pool (10): economic-function templates gated by BulkClass
(extraction/industrial/cold-chain/precision/information/civic) + universal
baselines + the foreign-import swerve. Guarantees the CI floor.
- Per-corridor baseline (8): each corridor's default cohesive look — core
cosmopolitan, north anglo-frontier, south lusophone, west germanic +
compact-cooperative, east dense-utilitarian, deep-frontier surname +
hardscrabble.
- Heritage sub-pools (10): deep-history callbacks tied to the D-237 heritage
taxonomy (scottish highland, west-african compound, iberian hacienda,
atlantic creole, nordic timber, central-european blok, east-asian temple,
vietnamese water village, afrikaans kraal, arab oasis).
Each template = holistic bundle: two-tier eligibility (hard gates
bulk_class/ubiquity/prosperity_bps + soft weight mods), zone_affinity over
the real DistrictType enum, allow/block tags from a shared ObjectTag
palette, and a D-235 visual_bundle with generic fallback parents. All
numerics integer basis-points (D-010).
Adds the D-232 CI guardrails to the baker (V-TT-01: >=5 templates eligible
per BulkClass; V-TT-02: no template >60% of pool weight) — both pass with
margin (23-24 eligible/class, 5% max share). Catalog can grow via the
bounded Gemma pass (#992); hero pins are #1017.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review fixes for the #1016 cultural pass (Hoshe/Paula/Miri):
- Kruger 60 (GJ 860A) xhosa -> cosmopolitan (Miri): GTTR describes an
Afrikaner/Xhosa/Zulu founding "without mapping cleanly onto any of
them" — the textbook genuinely-fused case, which taxonomy rule 4
resolves to cosmopolitan rather than one of the three. Commented.
- Altmark (GJ 357) financial_technocratic -> cosmopolitan (Paula):
reverts to the original shipped value; the GTTR reads as commercial
non-alignment, not credential-based technocracy.
- Kampala Gate (GJ 667B) + Moyale (GJ 1292) keep swahili but add inline
comments documenting that these are East-African-INTERIOR founders
(Baganda; Kenyan/Ethiopian Borana-Oromo) for which the taxonomy has no
dedicated token — swahili is the nearest available, NULL would fall to
the wrong corridor default. Gap logged for a follow-up taxonomy value.
Mwangaza (693) swahili is literally correct (coastal) — untouched.
- heritage-taxonomy-draft.md: stale "(38)" subheadings -> "(47)" to match
the actual canonical count (Hoshe/Miri doc typo).
Retracted: Pedra Seca (GJ 421B) xhosa — reviewer thought it lacked
authored backing, but its gttr.md explicitly states "Afrikaans and Xhosa
heritage"; pin kept.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completes the deferred cultural half of #1016 and migrates the heritage
vocabulary to the canonical 47-value taxonomy (D-237).
Migration (mechanical):
- _CULTURAL_HERITAGE replaced with the canonical 47-value set
(docs/.../heritage-taxonomy-draft.md). Renamed the 4 shipped hero
values to canonical: afrikaans_cape->afrikaans, french_provencal->
french, italian_northern->italian, norse_compact->nordic.
Content pass (authored from GTTR/name heritage triage, 6-sector fan-out):
- +139 new cultural_specialization pins and 1 change (Altmark
cosmopolitan->financial_technocratic), taking coverage 32 -> 171
across 54 distinct values. Each pin is grounded in an explicit GTTR
founding-community statement or system/feature name etymology, applied
only where founding heritage DIVERGES from the corridor baseline
(D-167/D-232); corridor-typical systems left NULL.
Distribution is now balanced and diverse — portuguese 15, german 12,
vietnamese 10, afrikaans 10 (no longer dominant post-#1019), then a long
tail filling the previously-missing slots (welsh, herero, czech, akan,
hungarian, konkan, afro_brazilian, cape_verdean, shona, arab/persian/
turkic, etc.).
Judgment calls (flagged for review):
- Kruger 60 + Pedra Seca -> xhosa (mixed SA founding; adds diversity).
Pedra Seca has a Portuguese name but Afrikaans/Xhosa GTTR founding —
name/heritage mismatch noted for a future content fix.
- Kampala Gate / Moyale / Mwangaza -> swahili as the nearest token for
East-African-interior heritage; taxonomy may want a dedicated value.
- Kept hero pins Kensho=scholarly, Keid=scholarly, Nyrheim=nordic.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GJ 680 has aperture_count=2 / gate_connections=2, linking two distinct
systems (Athabasca GJ 1289 and Enugu GJ 75) — but the prose, inherited
verbatim from the original Carnarvon page, described "one gate in, one
gate out, both the same gate" and "one aperture connecting to Enugu and
Athabasca" (self-contradictory). Reword the gttr and index to two gates
while keeping the system's low-through-traffic spur character (the
spur_end topology label and "nobody routes through here" identity are
unchanged). Resolves the deferred PR #146 review finding.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review fixes for the #1019 heritage rebalance:
- Marib's farm world Ghouta -> Ghawr (Miri): "Ghouta" carries strong
modern associations (2013 Damascus attack); Ghawr (the Jordan Rift
Valley, an irrigated lowland farming region) keeps the water-fed-
drylands sense without the resonance.
- Add dominant_faction = "independent" to GJ 914A / 508A / 1245B (Hoshe)
— all five rebalanced systems are self-governing independent
communities; uniform with siblings GJ 722 / 680 and clears V-FAC-01.
- catalog.md: fill GJ 914A -> Marib and GJ 722 -> Sığınak (Hoshe) — the
two anchor systems still showed em-dash placeholders.
- Marib gttr: name the second aperture neighbour Sığınak instead of the
bare "GJ 722" (Miri).
Pre-existing Golestan aperture/spur wording (reviewers split on whether
it is even wrong) is left for a separate content pass — not introduced
by this rename.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The pre-execution conversion plan and shipped-state addendum for the
South-African heritage rebalance: per-system field maps, the worked
gttr rewrites, the cross-reference cleanup list, and the rationale for
keeping load-bearing mystery systems out of scope.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>